纯css折叠菜单需用:checked伪类+兄弟选择器,input必须前置;避免display切换导致塌陷,改用visibility/opacity/max-height组合;媒体查询控制响应式,移动端子菜单应隐藏,设备旋转需监听matchmedia重置状态。

用 checkbox 实现纯 CSS 折叠菜单的核心限制
不能依赖 JavaScript 控制显隐,就得靠 :checked 伪类 + 兄弟选择器驱动样式切换,但前提是 DOM 顺序必须严格:<input type="checkbox" id="nav-toggle"> 必须出现在 <label for="nav-toggle"></label> 和目标菜单元素之前。否则 :checked ~ .nav-menu 根本选不到;常见错误是把 input 放在 label 里却没写 for,或反过来把 label 写在 input 前面。
display: none 导致父容器塌陷怎么办
直接对菜单用 display: none / display: block 切换,会让父容器高度瞬间归零,页面内容上跳——这不是动画问题,是布局重排。正确做法是组合使用:
-
visibility: hidden控制可访问性(屏幕阅读器仍能读) -
opacity: 0配合transition实现淡入淡出 -
max-height: 0+overflow: hidden避免撑开空间,同时保留过渡能力 - 展开时设
max-height: 500px(需预估最大高度,不能用auto)
媒体查询断点与菜单结构分离的关键点
桌面端显示完整横向菜单,移动端才启用折叠逻辑,这个判断必须交给 CSS 媒体查询,而不是 JS。否则设备旋转时状态不同步、SSR 渲染错乱。具体做法:
- 默认状态(大屏)下,
.hamburger和.nav-menu都设display: none - 仅在
@media (max-width: 768px)内让.hamburger显示,并让.nav-menu用:checked触发显隐 - 菜单内部用
flex-direction: column+width: 100%确保垂直铺满,别留白边
子菜单项错位、间距失控的常见原因
二级菜单(如悬停展开的下拉项)在移动端折叠模式下不该存在,但很多人忘了关掉。结果是点击汉堡后,一堆横向排列的 li 堆在一起,或者 position: absolute 的子菜单飞出视口。解决方式很直接:
- 所有子菜单(
.submenu或嵌套ul)在移动端统一设display: none - 如果需要移动端也支持多级展开,必须改用 JS 控制(因为
:hover在触摸设备不可靠),且每个子项要单独绑定click事件并加aria-expanded - 检查
padding/margin是否被父级flex的gap覆盖,移动端建议用padding-block替代padding-top/padding-bottom
checkbox 的勾选状态不会自动同步到新尺寸下的媒体查询逻辑里——它还是“已勾选”,但对应菜单可能已被隐藏。这时候必须监听 window.matchMedia 变化,手动重置 input.checked = false,否则用户会卡在“看不见菜单却以为它开着”的状态。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











