纯CSS汉堡菜单必须用input[type="checkbox"]作开关,配合label和nav的特定兄弟结构、伪元素绘图、max-height过渡及媒体查询适配,兼顾可访问性与响应式。

汉堡按钮的 HTML 结构必须包含 input[type="checkbox"]
纯 CSS 实现响应式导航菜单,关键在于用 input[type="checkbox"] 作为状态开关——它不依赖 JS,可被 :checked 伪类捕获,从而控制后续元素显隐。不要用 div 或 button 模拟开关,否则无法用纯 CSS 触发菜单展开。
常见错误是把 label 和 nav 放在不同容器里,导致选择器失效。正确结构必须保证:input 是 label 的前一个兄弟节点(或同级且能用 ~ 选择),且 nav 紧跟其后,才能用 input:checked ~ nav 控制显示。
-
input必须有id,label的for属性必须与之严格匹配 -
input需加aria-hidden="true"并设position: absolute; left: -9999px隐藏但保留可访问性 - 避免给
input设display: none,否则部分屏幕阅读器会跳过它
label 内部的三横线图标要用 span + ::before/::after 实现
用纯 CSS 绘制汉堡图标比插入 SVG 更轻量、更易响应式缩放,也避免额外 HTTP 请求。核心是让 label > span 作为中横线,再用两个伪元素生成上下横线,并统一用 transform 动画收拢为叉号。
容易踩的坑是没重置 user-select 和 pointer-events:点击区域若被伪元素遮挡或误触发文字选中,会导致点击失灵。所有参与图标的元素都应设 user-select: none 和 pointer-events: none(label 本身保留 pointer-events: auto)。
立即学习“前端免费学习笔记(深入)”;
- 三根线默认用
height: 2px+background,垂直间距用margin-top或top控制 - 动画需同时作用于
span和两个伪元素,且transition要写在常态下,而非:checked状态里 - 收拢为叉号时,上横线顺时针转 45°,下横线逆时针转 45°,中横线设
opacity: 0
nav 的响应式展开必须用 max-height + overflow-hidden 配合过渡
直接对 display 做过渡无效(display 不是可动画属性),所以得用 max-height 模拟高度变化。初始设 max-height: 0 + overflow-hidden,展开时设一个足够容纳所有菜单项的固定值(如 max-height: 300px)。
这个值不能设太小(内容被截),也不能设太大(动画时间拉长、收起时有明显空白延迟)。最佳实践是预估最大可能行数(比如 8 项 × 行高 48px ≈ 384px),再略留余量。
- 菜单项
a或li需设padding和line-height,避免视觉拥挤 - 移动端建议用
flex-direction: column布局,避免浮动或 inline-block 带来的换行问题 - 若菜单含下拉子菜单,需额外处理子项的
max-height和opacity过渡,不能只靠父级max-height
移动端适配必须用 @media (max-width: ...) 包裹全部交互样式
汉堡菜单只应在小屏生效;桌面端应始终显示完整导航。因此所有与 input:checked、label 图标变形、nav 展开相关的规则,都必须包裹在媒体查询内。漏掉这点会导致桌面端也能点出汉堡菜单,体验错乱。
断点值别硬写 768px 就完事。实际应根据设计稿中导航栏开始换行的宽度来定,用 Chrome DevTools 的设备模拟器拖动宽度实时观察,取临界点再加 1px(比如 624px 就比 623px 更稳妥)。
- 媒体查询外,
nav默认设display: flex或display: inline-flex,保持水平布局 -
label在桌面端设display: none,确保汉堡按钮完全隐藏 - 务必测试 iOS Safari —— 它对
max-height过渡的渲染有时滞后,可加will-change: max-height微调
Tab 到汉堡按钮后,展开菜单,焦点不会自动跳进菜单里。如果真要兼顾可访问性,就得加 JS 处理 focus 流,纯 CSS 方案在这里天然有缺陷。


















