最稳妥的纯CSS折叠菜单起点是input type="checkbox",需确保input在label前、正确绑定,用visibility+opacity+max-height实现过渡,媒体查询控制响应式断点,iOS/安卓需JS补救焦点和点击穿透问题。

用 input type="checkbox" 控制显隐,零 JS 实现基础折叠
纯 CSS 折叠菜单最稳妥的起点是 input type="checkbox",不是 button 或 div——因为只有表单控件自带可被 :checked 捕获的状态。关键点在于 DOM 顺序:input 必须在 label 之前,且用 for 属性或包裹方式绑定,否则点击汉堡图标无效。
常见错误:
-
<label for="nav-toggle">☰</label><input id="nav-toggle" type="checkbox">——~选择器选不到后面的.nav-menu -
<label><input type="checkbox">☰</label>—— 隐式关联可行,但若input被包裹在其他元素里(如span),可能失效
正确结构示例:
<input id="nav-toggle" type="checkbox"> <label for="nav-toggle">☰</label> <nav class="nav-menu">...</nav>
:checked ~ .nav-menu 显隐时别用 display: none
用 display: none 会让 .nav-menu 脱离文档流,父容器高度塌陷,导致下方内容上跳;同时 height: auto 无法参与 CSS 过渡动画。
立即学习“前端免费学习笔记(深入)”;
推荐写法(兼顾过渡与布局稳定):
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
-
visibility: hidden+opacity: 0+max-height: 0+overflow: hidden -
:checked ~ .nav-menu中设为visibility: visible、opacity: 1、max-height: 500px(值需略大于菜单最大可能高度) - 过渡用
transition: opacity 0.3s, max-height 0.3s ease-out,避免用height
媒体查询控制“何时显示汉堡按钮”
响应式不是只靠 JS 切换类名,核心逻辑应由 CSS 媒体查询接管:桌面端默认显示完整导航,移动端才启用折叠逻辑。
典型断点写法:
-
@media (max-width: 768px)下,对.nav-menu设flex-direction: column、width: 100% -
.nav-toggle在此断点下设为display: block,桌面端保持display: none - 确保
input#nav-toggle始终存在于 DOM 中(不靠 JS 插入),否则媒体查询切换时状态丢失
别把“是否显示汉堡”交给 JS 判断窗口宽度——CSS 媒体查询更可靠,且能响应设备旋转。
移动端点击穿透与焦点残留必须用 JS 补救
纯 CSS 方案在 iOS Safari 或部分安卓浏览器上有两个硬伤:
- 点击
label后,input获得焦点但不自动失去,连续点击可能失效 - 菜单内链接若紧贴
label,一次点击可能触发两次跳转(label激活 checkbox + 链接本身跳转)
最小化 JS 干预方案:
- 给
input#nav-toggle绑定focusout事件,手动blur() - 菜单内链接加
pointer-events: none,等菜单完全展开后再移除(用transitionend监听) - 避免在
label内直接放a标签,所有导航链接统一放在.nav-menu内部
真正的难点不在怎么展开,而在状态同步——设备旋转时 checkbox 状态不会自动重置,必须监听 orientationchange 或 resize 手动干预,这点常被忽略。


















