移动端可展开菜单max-height动态过渡延迟问题求解
移动端展开菜单收起延迟问题的解决方案
问题场景与代码示例
我有一个网站头部的移动端可展开菜单,运行逻辑如下:
HTML代码
<header class="drop-shadow"> <nav class="container"> <!-- Logo --> <h2>LOGO</h2> <!-- Menu Button --> <button id="menu-button" class="menu-button">☰</button> <!-- Menu --> <ul id="menu" class="menu"> <li class="menu-item"> <a href="/" class="menu-link active">Home</a> </li> <li class="menu-item"> <a href="/blog" class="menu-link">Blog</a> </li> <li class="menu-item"> <a href="/about" class="menu-link">About</a> </li> </ul> </nav> </header>
CSS代码
body { margin: 0; padding: 0; } header { background-color: #333; color: #fff; padding: 0 1rem; } nav { display: flex; justify-content: space-between; align-items: center; height: 80px; } .menu { background-color: #888; position: absolute; top: 80px; left: 0; margin: 0; padding: 0; width: 100%; text-align: center; max-height: 0; overflow: hidden; transition: max-height 0.3s ease; } .menu.open { max-height: 100vh; } .menu-item { list-style-type: none; } .menu-item:not(:last-child) { border-bottom: 1px solid #333; } .menu-item a { display: block; padding: 1rem; color: #fff; } /* 大屏端菜单始终显示样式 */ @media (min-width: 768px) { .menu-button { display: none; } .menu { position: static; max-height: none; overflow: visible; display: flex; } }
JavaScript代码
const menuButton = document.getElementById("menu-button"); const menu = document.getElementById("menu"); menuButton.addEventListener("click", function() { menu.classList.toggle("open"); });
当前问题
菜单点击后展开即时可见,但因设置的max-height: 100vh远大于实际高度,收起时会有一段延迟才会出现可见的收起效果。
已知常用方案是通过JavaScript动态设置max-height为菜单实际高度,但该方式会给元素添加内联样式;而菜单是响应式的,在大屏端始终显示,若切换窗口尺寸后,内联max-height会导致布局错乱。同时不想硬编码max-height,因为菜单项会定期变化,高度也会随之改变。
求无需通过内联样式动态设置max-height,就能实现菜单即时可见收起的方法?
解决方案:CSS自定义属性配合JavaScript计算高度
这种方法既可以动态获取菜单实际高度,又不会产生干扰响应式布局的内联样式,而是通过CSS变量传递高度值:
修改后的CSS代码
body { margin: 0; padding: 0; } header { background-color: #333; color: #fff; padding: 0 1rem; } nav { display: flex; justify-content: space-between; align-items: center; height: 80px; } .menu { background-color: #888; position: absolute; top: 80px; left: 0; margin: 0; padding: 0; width: 100%; text-align: center; max-height: 0; overflow: hidden; transition: max-height 0.3s ease; /* 定义CSS变量存储菜单实际高度 */ --menu-height: 0; } .menu.open { /* 使用计算出的实际高度作为max-height */ max-height: var(--menu-height); } .menu-item { list-style-type: none; } .menu-item:not(:last-child) { border-bottom: 1px solid #333; } .menu-item a { display: block; padding: 1rem; color: #fff; } /* 大屏端重置变量,避免布局干扰 */ @media (min-width: 768px) { .menu-button { display: none; } .menu { position: static; max-height: none; overflow: visible; display: flex; --menu-height: auto; } }
修改后的JavaScript代码
const menuButton = document.getElementById("menu-button"); const menu = document.getElementById("menu"); // 计算并设置菜单实际高度到CSS变量 function setMenuHeight() { const height = menu.scrollHeight; menu.style.setProperty('--menu-height', `${height}px`); } // 初始化+窗口 resize 时重新计算高度 setMenuHeight(); window.addEventListener('resize', setMenuHeight); menuButton.addEventListener("click", function() { menu.classList.toggle("open"); // 展开时重新计算高度,适配菜单项动态变化的场景 if (menu.classList.contains('open')) { setMenuHeight(); } });
方案优势
- 无内联样式干扰:通过
setProperty设置的是CSS自定义属性,而非直接修改元素的max-height内联样式,大屏媒体查询中可轻松重置--menu-height为auto,避免布局错乱。 - 适配动态菜单项:每次点击展开或窗口尺寸变化时都会重新计算菜单高度,菜单项更新后只需调用
setMenuHeight()即可同步高度。 - 收起无延迟:
max-height设置为菜单实际高度,收起时过渡动画从实际高度直接降到0,消除延迟问题。
内容的提问来源于stack exchange,提问作者YangTegap
相关产品推荐
相关产品推荐

