响应式侧边导航应使用 max-width: 768px 媒体查询配合 transform: translateX(-100%) 隐藏,避免 display: none;用 checkbox + label 实现纯 CSS 开关,确保可访问性(aria-expanded、tabindex、足够点击热区)。

用 @media 切换侧边导航显示状态
响应式侧边导航不是靠 JS 控制显隐,而是靠媒体查询在不同视口宽度下切换 display 或 visibility。关键在于断点选择要匹配真实设备习惯:小屏(max-width: 768px)隐藏,中大屏恢复。别用 480px 这种过时断点,现在大部分手机横屏都超 768px,硬卡太窄会导致桌面端用户缩放后意外触发隐藏。
常见错误是只写 display: none,结果导航内容完全脱离流、焦点丢失、屏幕阅读器不可访问。更稳妥的做法是搭配 position: absolute + clip-path 或 transform: translateX(-100%),保留可访问性。
- 断点推荐用
max-width: 768px,兼顾 iPad 竖屏和主流手机 - 隐藏时优先用
transform: translateX(-100%)而非display: none - 确保
nav容器有明确的width和transition,否则动画会突兀
用 <input type="checkbox"> 模拟开关行为
纯 CSS 实现“点击展开/收起”,本质是利用 checkbox 的 :checked 状态驱动样式变化。它比 :hover 更可靠,支持触屏、键盘空格切换,且不依赖 JS。但必须注意 DOM 结构:input 必须在导航容器之前,且用相邻兄弟选择器(~)或通用兄弟选择器(+)关联目标元素。
容易踩的坑是 label 没包住 input,或用了 for/id 但 id 写错,导致点击无响应;还有人把 input 设为 display: none 后忘记加 position: absolute,结果被其他元素遮挡、无法触发。
立即学习“前端免费学习笔记(深入)”;
-
input必须放在nav前面,且与导航容器同级 - 用
input:checked ~ nav匹配后续兄弟元素,别用后代选择器 - label 标签要包裹
input,或正确设置for属性指向input的id - 隐藏
input推荐用position: absolute; opacity: 0; pointer-events: none;,而非display: none
移动端点击区域太小导致无法触发 :checked
很多实现里,只给 checkbox 加了 opacity: 0,但没扩大点击热区,用户实际要点的位置是空白或图标边缘,尤其在小屏上极易误操作。这不是 bug,是样式没补全。
解决方案是让 label 承担点击职责,并设足够大的 padding 或 min-height。如果用 icon 当按钮,记得给 icon 外层的 label 加 display: inline-flex 和 align-items: center,避免垂直对不齐。
- label 必须设
cursor: pointer,让用户感知可点 - label 最小高度建议 ≥ 44px(iOS 触控最小推荐值)
- 若用 SVG 图标,确保
svg本身不拦截 pointer-events,必要时加pointer-events: none - 测试时真机点几次,别只靠鼠标悬停模拟
键盘与屏幕阅读器支持常被忽略
纯 CSS 方案默认不处理键盘焦点和 ARIA 状态,屏幕阅读器用户按 Tab 键可能跳过整个导航,或者不知道当前是展开还是收起。这不是“能用就行”的问题,是合规性和可用性底线。
必须手动补上 aria-expanded 和 aria-controls,并通过 JS(极少)或伪类联动更新——但注意:CSS 无法修改属性值,所以得靠 JS 监听 checkbox 变化来同步 ARIA。不过,如果项目允许极简 JS,只写一行 checkbox.addEventListener('change', e => nav.setAttribute('aria-expanded', e.target.checked)) 就够了,不算破戒。
- nav 元素必须有
id,label 的aria-controls要指向它 - nav 上加
aria-expanded="false"初始值,JS 更新它 - checkbox 本身加
aria-label="切换侧边导航",别只靠视觉图标 - 不写 JS 的话,至少保证
tabindex="0"和role="button"让键盘可聚焦










