必须用,因为:checked伪类是css唯一能稳定捕获用户交互状态的机制,配合~或+选择器实现纯css显隐控制;button或div无原生状态,css无法监听,导致跨浏览器失效。

不用 JavaScript 就能做出可靠响应式顶部导航,但必须用 <input type="checkbox"> 控制展开状态——其他方案在 JS 加载失败、iOS Safari 或 IE11 下大概率失效。
为什么 <input type="checkbox"> 不可替代
CSS 的 :checked 伪类是唯一能在无 JS 情况下被选择器(如 ~ 或 +)稳定捕获的状态。用 <button></button> 或 <div> 模拟开关,CSS 根本监听不到“点击后是否激活”,结果就是点一下跳转、点两下没反应、或只在 Chrome 里动一下。
<ul>
<li>
<code><input type="checkbox"> 必须放在 <label></label> 前面,且用 for 属性绑定,否则 iOS 触控区域可能小于 44px,点击失灵
display: none 隐藏 checkbox——它会失去交互能力;应改用 opacity: 0; position: absolute;
:checked ~ .nav-menu,无需 polyfill,但 IE11 不支持 gap,得回退到 margin-right 并加 li:not(:last-child)
flex 布局中导航项换行/压缩的修复要点
很多人一写 nav ul { display: flex; } 就以为完事,结果小屏上文字被压扁、图标错位、甚至横向溢出滚动条——问题出在默认 flex-shrink: 1 和没设 flex-wrap。
- 每项加
flex: 0 0 auto,禁止缩放,文字变长也不变形 -
nav ul必须设flex-wrap: wrap,窄屏自动折行,比强行单行更健壮 - 用
gap: 1rem控制间距,比给每个li加margin-right更干净;但 IE11 不支持,得手动写li:not(:last-child) { margin-right: 1rem; } - 右对齐登录项?直接给对应
li加margin-left: auto,别用float: right或position: absolute—— 会破坏 Flex 流
下拉菜单定位偏移的常见原因与解法
下拉菜单总飘到页面顶部、或滚动时脱离触发项?大概率是父容器没设 position: relative。
- 每个含下拉的
li必须加position: relative,否则position: absolute的子菜单会往上找最近已定位祖先,甚至落到上 - 下拉项用
top: 100%; left: 0;,比写死top: 44px更可靠——导航栏高度变化时自动对齐 - iOS Safari 中
transform+position: fixed易闪烁,改用position: sticky; top: 0;更稳 - 子菜单结构必须是
li > ul(直接子元素),平级或外置会导致 CSS 选择器失效、焦点管理失控
移动端汉堡菜单展开动画卡顿或截断
用 max-height 做过渡动画最常用,但写死数值容易出问题:下拉项增减后高度不够,动画直接砍掉一半内容。
-
.nav-menu默认设max-height: 0; overflow: hidden;,避免用display: none—— 它无法触发 CSS 过渡 - 触发时靠
input:checked ~ .nav-menu设max-height: 300px,这个值需略大于所有子项总高;max-height: fit-content在过渡中不生效,别试 - 如果菜单项动态变化(比如权限控制显隐),预估高度不可靠,就得用 JS 补充计算,纯 CSS 无解
- 别给
href="#"——点完页面滚顶,且语义错误;空链接建议直接移除href,加role="button"补无障碍
真正难的不是写出能动的导航栏,而是让所有设备、所有状态(hover / focus / checked / reduced-motion)、所有辅助技术都一致工作——nav + ul + li 结构不是为了“好看”,而是读屏器依赖这套语义链判断 Tab 顺序和菜单总数。漏掉一个 position: relative 或多写一个 display: none,就可能让整套逻辑在某个浏览器里彻底失效。











