纯css多级下拉菜单需同时满足:所有可展开li设position:relative、hover选择器逐层写全、父级与子菜单间无缝隙、支持:focus-within无障碍访问,缺一不可。

纯 CSS 多级下拉菜单能“流畅”,但前提是 hover 触发链不断、定位上下文不丢、视觉路径无空隙——缺一不可,否则鼠标一移就闪退,三级根本展不开。
父级 li 必须显式设 position: relative
子菜单用 position: absolute 却飘到左上角?不是 top: 100% 写错了,是它根本没找到定位基准。浏览器会逐层向上找最近的已定位祖先,li 默认是 static,不构成定位上下文。
- 所有可能展开子菜单的
li(包括一级、二级、三级)都得加position: relative - 别指望
display: flex或float容器自动创建定位上下文——它们不会 - 禁止给
body或html加position: relative,这会让所有绝对定位元素以整个视口为参考,彻底失控
:hover 选择器必须写全层级,不能“穿透”
CSS 的 :hover 不会自动维持跨多层 DOM 的悬停状态。漏写一层,下一级就卡死。比如三级菜单,不是写了 .menu > li:hover ul ul 就完事——它会匹配任意嵌套三层的 ul,甚至误展非目标项。
- 二级:用
.first-level-menu > li:hover > .second-level-menu - 三级:必须补中间层,写成
.second-level-menu > li:hover > .third-level-menu - 如果 HTML 是
<li class="has-sub">Item<ul></ul> </li>,选器就得是.has-sub:hover > ul,不是li:hover ul - 避免宽泛选择器如
ul ul ul,它无法区分哪一级该响应
鼠标移向子菜单时闪退?不是动画问题,是视觉断点
这不是 transition 没配好,而是父 li 和子 ul 之间存在像素级空隙。鼠标一旦离开触发区域,:hover 立刻失效,菜单瞬间收起。
- 二级菜单用
top: 100%后,在父li上加padding-bottom: 2px或margin-top: -1px把缝隙物理缝合 - 三级右向展开时,用
left: 100%; top: -1px对齐二级项顶部,避免垂直偏移产生新空隙 - 禁用
visibility: hidden替代display: none——它仍占布局空间,hover 后可能引发文字跳动或宽度塌缩 - 子菜单统一设
min-width: 100%,防止内容窄导致鼠标悬停区域中断
移动端和键盘用户看不到你的 hover 菜单,这不是 bug 是设计缺陷
iOS/Android 不支持 hover;键盘用户 Tab 进入后焦点直接跳走。仅靠 :hover 的菜单在这些场景下等于不存在。
- 必须同时写:
.has-submenu:hover > .submenu和.has-submenu:focus-within > .submenu - 每一级可展开的
li都要支持:focus-within,否则键盘导航进不去二级 - 用
@media (hover: none), (pointer: coarse)主动禁用 hover 规则,只保留:focus-within和 JS 控制的[data-open="true"] - 别在媒体查询里写
.submenu { display: block }——这会让所有子菜单默认展开,失去交互控制
最常被忽略的点:所有层级的 position: relative 和 :focus-within 支持必须同步到位。少一个,桌面端就闪退,无障碍就失效,响应式就崩盘——这不是细节,是生效前提。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











