菜单“消失”是因 md:flex-row 下父容器高度坍缩,需加 min-h-16 防塌陷;hidden 与 md:flex-row 混用会导致显示不可控及动画中断,应分层控制显隐并用 opacity-0/max-h-0 模拟过渡;移动端菜单须 absolute 定位、relative 父容器及键盘可访问支持;peer-checked 无法响应视口变化或路由跳转,需轻量 JS 补足状态同步。

为什么直接用 flex-col 和 md:flex-row 会导致菜单“消失”
根本不是类没生效,而是 flex-row 下父容器高度坍缩:小屏时 flex-col 让子项撑高容器,中屏切 md:flex-row 后,若父容器没设高度约束,就可能塌成一条线甚至不可见。浏览器 computed styles 里 flex-direction 确实变了,但容器本身没内容或 min-height,视觉上就“没了”。
实操建议:
-
nav或菜单包裹容器必须加min-h-16(或h-16),防止 flex 容器塌陷 - 别混用
hidden和md:flex-row控制显隐——前者管“展不展开”,后者只管“怎么排列” - 用开发者工具检查断点生效情况:hover 到
md:flex-row类上,看媒体查询是否命中(@media (min-width: 768px))
hidden 和 md:flex 搭配时容易闪动或错位
因为 hidden 是 display: none,而 md:flex 只在中屏生效,两者无覆盖逻辑。小屏时 hidden 生效;中屏时两个类共存,最终是否显示取决于 JIT 编译顺序或 CSS 权重,不可控。更糟的是 hidden 会中断所有 transition 动画(display 不可动画)。
正确做法是分层控制:
立即学习“前端免费学习笔记(深入)”;
- 主菜单用
hidden md:flex:默认隐藏,中屏起显示为 flex - 汉堡按钮用
md:hidden:默认显示,中屏及以上隐藏 - 移动端菜单容器用
flex md:hidden:默认显示 flex,中屏隐藏 - 动画必须绕开
hidden,改用opacity-0+max-h-0+overflow-hidden模拟,且过渡写在元素自身上
移动端菜单展开后位置错、遮挡内容或焦点不可达
常见原因是没加定位和可访问性支持:flex 默认是文档流内布局,下拉菜单会把页面往下推,而不是“浮”在顶部;键盘用户 Tab 也进不去。
实操要点:
- 移动端菜单容器必须加
absolute top-full left-0 w-full bg-white shadow-lg,脱离文档流 - 确保父容器有
relative(比如包裹button的div),否则top-full基准错乱 - 加
focus-within:outline-none和tabindex="-1",点击汉堡后菜单获得焦点,键盘用户可用 Tab 进入 - 内容过长时加
max-h-96 overflow-y-auto,防溢出
纯 CSS 实现折叠/展开时状态不同步、缩放窗口后卡住
peer-checked 是纯 CSS 状态,不感知视口变化。从手机横屏切到桌面宽度时,<input type="checkbox"> 仍保持勾选,侧边栏就卡在展开态;按 Esc 或路由跳转后也不会自动收起。
这已经超出 CSS 能力边界:
-
<input>必须放在按钮和菜单前,且三者同级相邻,id和for必须精确匹配 - 桌面端需用
lg:translate-x-0 lg:opacity-100强制重置,不能只依赖peer-checked - 真正难的不是写对类名,而是让状态与用户预期一致:点击触发勾选、Esc 收起、跳转后关闭——这些得用轻量 JS 补足,比如监听
keydown或popstate
最易被忽略的是:如果汉堡按钮和菜单不在同一 DOM 层级(比如按钮在 header 右上角,菜单在 body 底部),peer 完全失效,这时硬套 CSS 反而浪费时间。


















