纯css响应式导航折叠最稳方案是checkbox+~选择器控制max-height过渡,需确保input与.menu同级、设足够max-height值、媒体查询双向覆盖桌面端、js同步aria-expanded属性。

纯 CSS 实现响应式导航折叠,checkbox 是目前最稳定、零 JS 依赖的方案,但“能跑通”和“真可用”之间差着三个坑:结构错位、选择器失效、动画卡死。关键不是写对了 :checked,而是让浏览器真的识别并触发它。
input:checked ~ .menu 不生效?先查 HTML 结构层级
绝大多数“点了没反应”问题,根源是 input 和目标菜单不在同一 DOM 层级,或中间插入了无法被 ~ 覆盖的元素。
-
input必须和.menu是同级兄弟元素(即父容器相同),不能一个在nav外、一个在nav内 - 如果
label插在input和.menu中间,input:checked + .menu会失败,必须改用input:checked ~ .menu - 不要把
input套进label里再设display: none——部分 Safari 会跳过渲染该 checkbox 的状态变更 - 推荐结构:
<input type="checkbox" id="nav-toggle"><label for="nav-toggle"></label><nav class="menu"></nav>
max-height 过渡不动?别碰 display: none
display 属性没有中间状态,加 transition 完全无效。所有“滑动展开”效果都得靠 max-height + overflow: hidden 配合。
- 关闭状态设
max-height: 0,同时必须加overflow: hidden,否则内容会撑开容器 - 展开状态不能写
max-height: auto(无法过渡),要设一个“够用但不过量”的固定值,比如max-height: 400px - 若菜单含异步加载图片或字体,初始
max-height不够会导致底部截断;可加padding-bottom: 1px触发重排微调 - 避免用
visibility: hidden替代,它不触发重排,动画会顿挫或直接跳变
桌面端菜单不显示?媒体查询要双向覆盖
移动端折叠是常态,但桌面端必须主动“解除折叠”,否则用户打开网页就看不到导航。
- 默认写法应移动优先:
#nav-toggle { display: none; },小屏下靠@media (max-width: 768px)控制折叠逻辑 - 桌面端需用
@media (min-width: 769px)显式设置:#nav-toggle:checked ~ .menu { max-height: 400px; },并确保.menu在大屏下有正常布局(如display: flex) - 千万别只写小屏逻辑,忘了大屏下要让菜单“默认展开”——否则 checkbox 默认未勾选,
.menu就一直max-height: 0
屏幕阅读器读不出状态?aria-expanded 得靠 JS 补
纯 CSS 方案对无障碍完全不友好。checkbox 状态变了,但菜单区域没有任何语义变化,读屏软件无法告知用户“当前菜单已展开”。
- 必须用 JS 监听
#nav-toggle的change事件(不是click),更新.menu的aria-expanded属性 - 初始加载时也要同步一次:
menuEl.setAttribute('aria-expanded', toggleEl.checked) - 这个步骤不是可选项,是 WCAG 4.1.2 合规硬性要求,否则实际使用中会被反复询问“这个按钮控制什么?现在状态如何?”
真正难的不是写出那段 input:checked ~ .menu { max-height: 400px; },而是确保 checkbox 被正确触发、max-height 值足够又不过载、桌面端逻辑不被遗忘、以及无障碍属性不被跳过——这四点漏掉任何一环,都会让“无 JS 折叠”变成半残体验。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











