移动端导航默认用 display: none + 媒体查询隐藏,配合 checkbox+label 实现无 JS 折叠;禁用 details 和 :hover,避免 iOS Safari 与微信 X5 兼容问题。

移动端导航默认收起,用 display: none + 媒体查询控制显隐
小屏下导航栏必须默认隐藏,否则会挤占内容区、触发横向滚动。别指望 JS 加载完再隐藏——首屏就露出来,体验直接崩。
关键写法:@media (max-width: 768px) { .nav-menu { display: none; } },配合一个可见的汉堡按钮(☰)作为触发入口。这个 display: none 必须写在 CSS 里,不能靠 JS 切 class 动态加,否则页面加载瞬间会闪出一帧完整菜单。
-
.nav-menu是包裹所有导航项的<ul></ul>或<nav></nav>容器 - 汉堡按钮本身要设
display: block,且仅在max-width: 768px下生效 - 桌面端不写
display: none,让它自然流式显示;移动端才强制隐藏
折叠菜单展开用 input[type="checkbox"] + label + ~ 兄弟选择器
别用 details 嵌套做多级下拉——iOS Safari 和微信 X5 内核根本不认子 details,状态不同步是常态。也别用 :hover,手机上压根没 hover。
最稳方案:一个隐藏 <input type="checkbox" id="menu-toggle">,紧挨着它放 <label for="menu-toggle">☰</label>,后面紧跟 <nav><ul>...</ul></nav>。CSS 写成:input#menu-toggle:checked ~ nav ul { display: block; }
立即学习“前端免费学习笔记(深入)”;
-
input和label之间**不能有换行、空格或其它标签**,HTML 空白符会被解析为文本节点,~就失效 -
nav ul必须是label的**直接兄弟节点**,中间插个<div> 就断链 <li>展开后菜单需设 <code>position: absolute或top: 100%,否则会撑开布局导致页面跳动 - 每层
ul都要加role="menu",每个可点击项(a或button)加role="menuitem" - 带子菜单的
li必须加aria-haspopup="true"和初始aria-expanded="false" - 移动端必须重置所有子级
.submenu为display: none,不能留“半开”状态 - 别给
details直接设height: 0——会压垮内部流式内容,布局错乱 - 如果用
input[type="checkbox"]控制,动画规则要写在input:checked ~ .submenu下,不是.submenu自身 - 移动端收起时,除了
max-height,还得同步设pointer-events: none防止触摸穿透
子菜单层级必须用 ul 嵌套在父 li 内部,不能脱离结构
多级菜单不是靠 JS 拼 DOM 或 CSS 绝对定位硬凑出来的。浏览器和屏幕阅读器只认 DOM 层级关系:子 ul 必须是父 li 的**直接子元素**,否则键盘 Tab 会跳过、aria-expanded 同步失败、CSS 选择器匹配错层。
正确结构:<li>Products<ul><li>Laptops</li></ul>
</li>;错误结构:<li>Products</li>
<ul><li>Laptops</li></ul>(子 ul 在 li 外)或 <div>Products</div>
<ul>...</ul>(插入 div 破坏父子链)
折叠动画别用 display: none 切换,改用 max-height + overflow: hidden
直接切 display: none 会导致过渡动画完全丢失,用户感知生硬。但也不能给 height 设固定值——内容高度不可控,容易裁剪或留白。
稳妥做法:默认设 max-height: 0 + overflow: hidden,展开时设 max-height: 500px(足够高,但别设 none),再加 transition: max-height 0.3s ease。这样既平滑,又不依赖 JS 计算高度。
@media (max-width: 768px) 显式重置所有 .submenu 的 display 或 max-height,否则折叠状态混乱、焦点路径断裂、内容区被挤压到无法操作。



















