移动端菜单需用 css+js 实现折叠动画,因原生 details 元素在 ios safari 上卡顿、不可自定义高度且不支持 touch 事件穿透;须测子菜单 scrollheight 后设置 max-height 动画,并配合 touch-action: manipulation 和完整 aria 语义确保可访问性。

移动端菜单需要自己写折叠动画,details 不够用
原生 details 元素在 iOS Safari 上动画卡顿、无法自定义展开高度、不支持 touch 事件穿透控制,实际项目中基本没法直接用。必须用 CSS + JS 控制 max-height 或 transform 才能保证滑动顺滑、点击响应及时。
max-height 动画要设具体像素值,不能用 auto
CSS 过渡对 max-height: auto 无效,浏览器不知道终点是多少。得先用 JS 测出子菜单真实高度,再设为 max-height 值:
const menu = document.querySelector('.mobile-menu');
const submenu = menu.querySelector('.submenu');
const height = submenu.scrollHeight + 'px'; // 注意是 scrollHeight,不是 offsetHeight
submenu.style.maxHeight = height;
- 测高必须在元素 display: block 状态下进行(如果初始 hidden,需临时设为 opacity: 0 + visibility: visible)
- 过渡时间建议 ≤ 300ms,否则在低端安卓机上会明显拖影
- 收起时设
max-height: 0后,需监听transitionend再设display: none,否则影响下次展开
点击区域必须包含 touch-action: manipulation
移动端双击缩放、300ms 点击延迟会导致菜单响应迟钝。每个可点击菜单项都要加:
.menu-toggle, .submenu-item {
touch-action: manipulation;
}
- 不加这句,iOS 上点开菜单可能要等半秒才响应
- 如果用了
preventDefault()拦截 touchstart,反而容易误触页面滚动,不如直接用manipulation - 不要对整个菜单容器设该样式,只作用于按钮和链接
键盘与屏幕阅读器支持不能靠 JS 补救
折叠菜单必须有语义化结构,否则视障用户根本不知道菜单存在或当前状态:
- 触发按钮加
aria-expanded="false",展开后改为"true" - 子菜单加
role="region"和aria-labelledby指向按钮 id - 用
tabindex="-1"控制子菜单内链接的聚焦顺序,避免展开前也能 tab 进去 - 别用
visibility: hidden隐藏菜单——屏幕阅读器仍会读;要用aria-hidden="true"+display: none
动效只是锦上添花,可访问性才是折叠菜单能被真正使用的底线。测一测 VoiceOver 或 TalkBack 下能否说出“主菜单已展开,共 5 项”,再看键盘 tab 是否按视觉顺序走 —— 这两件事做不好,动效再丝滑也没意义。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











