+是最轻量语义方案,原生支持交互与无障碍,但iOS 15.4前无open动画;需自定义动画或兼容老iOS时改用++配合JS和CSS实现。
用 + 是最轻量、语义最准的方案,原生支持展开/收起、键盘操作(空格/回车)、屏幕阅读器,且无需 JS 就能工作。但要注意:iOS Safari 15.4 之前不支持 open 属性动画,且无法用 CSS 精确控制箭头方向或过渡效果。
如果需要自定义动画、多级嵌套或兼容老版本 iOS,就得换为 + + 结构,靠 JS 切换 aria-expanded 和类名,再用 CSS 控制 max-height 或 transform 实现折叠。
纯 CSS 折叠动画不能直接对 height: auto 做过渡,否则无效。必须用以下任一方式:
max-height 设一个足够大的固定值(如 max-height: 500px),并配合 overflow: hidden;缺点是内容超长时会截断transform: scaleY() + origin-top,搭配 opacity,性能更好,但需确保父容器有 overflow: hidden
clip-path(如 clip-path: inset(0 0 100% 0)),动画更自然,但 Safari 15.2+ 才稳定支持所有方案都必须显式声明 transition,且避免在 :focus-within 或伪类中漏掉过渡属性。
移动端常因点击区域太小、touch-action: manipulation 缺失或 pointer-events 错误导致菜单点不响或连点失效。务必检查:
的 type="button" 是否明确设置,防止表单提交干扰pointer-events: none(比如为了透传背景点击)focus-visible 区分键盘与鼠标焦点,避免移动端误加 outlinebutton.focus()),否则键盘用户会卡在页面底部不要只按设备宽度切,而是按内容密度决定折叠时机。例如:
@container(需父容器设 container-type: inline-size)替代媒体查询,让菜单响应其容器宽度而非视口min-width: 768px 就强制展开——平板横屏可能只有 834px 宽,但字体放大后实际可用空间更小真正可靠的判断依据是:导航栏是否发生换行或文字被压缩。可借助 resize-observer 监听容器尺寸变化,动态切换模式。
.nav-menu {
--menu-height: 0;
max-height: var(--menu-height);
overflow: hidden;
transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.nav-menu[aria-expanded="true"] {
--menu-height: 300px;
}
复杂点在于:动画节奏要匹配手指操作反馈感,太快显得突兀,太慢又像卡顿;而最容易被忽略的是,折叠菜单一旦进入无障碍树,就必须同步维护 aria-hidden 和 tabindex 状态,否则 TalkBack 或 VoiceOver 会读出不可见项。