三级菜单纯CSS可行但需三条件:父级li设position:relative、子菜单初始display:none、:hover选择器链完整嵌套(如.menu>li:hover>ul>li:hover>ul),缺一第三级即消失。

三级菜单用纯 CSS 实现可行,但必须写全 :hover 链、父级加 position: relative、子菜单初始设 display: none——漏任一条件,第三级就消失。
为什么三级菜单 hover 后不显示
不是浏览器不支持,而是 CSS 的 :hover 不会“穿透”中间层级自动维持状态。它只响应鼠标直接悬停的元素,且仅对 DOM 树中连续嵌套的后代生效。
- HTML 结构必须是
<li><ul><li><ul></ul></li></ul></li>,不能把三级<ul>拆到 body 下(比如 Vue 的Teleport) - CSS 选择器必须显式写出每一级触发路径,例如:
.menu > li:hover > ul > li:hover > ul,少一个:hover或一个>,第三级就卡死 - 二级
<li>必须设position: relative,否则它的子<ul>(即三级菜单)用position: absolute时会相对于 body 定位,飘出视口 - 别用
visibility: hidden或opacity: 0替代display: none初始隐藏——前者仍占交互区域,鼠标移入时无法稳定触发:hover
如何写正确的三级 hover 选择器链
关键在“逐层绑定”,不能靠模糊匹配,也不能跳过中间节点。
- 一级触发:用
.main-nav > li:hover > .second-level - 二级触发:必须基于上一级已展开的容器,写成
.second-level > li:hover > .third-level - 禁止写
.main-nav li:hover .third-level:它会匹配所有后代,导致鼠标离开一级后三级还挂着;也禁止写.main-nav > li:hover .third-level:缺少二级:hover约束,第三级根本不会等你移过去 - 如果二级菜单项带类名
has-sub,优先用.has-sub:hover > .third-level,比泛用li:hover更精准,避免误触无子菜单的项
鼠标移向三级菜单时闪退怎么办
这不是动画问题,是悬停区域出现物理断点——一级 <li> 和二级 <ul> 之间有空隙,鼠标经过时 :hover 立刻失效。
立即学习“前端免费学习笔记(深入)”;
- 最稳方案:给二级
<li>加padding-bottom: 12px,再用margin-bottom: -12px抵消布局影响,让悬停热区向下延伸覆盖空隙 - 别依赖
transition-delay隐藏:它只延迟动画开始时间,不延长:hover生效周期 - 禁用
display: none直接过渡:CSS 无法对display做平滑动画,若要淡入滑下,得配合opacity和transform,且过渡声明必须写在子菜单自身上,例如.third-level { transition: opacity 0.18s ease, transform 0.18s ease; } - 移动端不支持
:hover,这类菜单默认不可用;如需兼容,必须用<input type="checkbox">或 JS 切换 class,不能硬撑
容易被忽略的盒模型细节
菜单宽度错乱、文字换行、右边界被截断,往往和 display 无关,而是 white-space、min-width 或继承样式失控。
- 三级
<ul>必须设min-width: 100%,否则窄屏下可能比二级项还窄 - 菜单项内含长英文或数字时,加
white-space: nowrap防止意外折行撑宽容器 - 避免给
<ul>设width: 100%:它会继承父级 padding,实际宽度超限 - 如果一级用了
text-align: center,三级菜单会继承,需显式重置为text-align: left - IE11/旧 Edge 对
:hover动态插入内容支持差,可加:focus-within兜底,但需确保触发元素有tabindex="0"或语义化 role
真正难的不是写三级,而是让每一级的定位上下文、悬停热区、盒模型行为全部对齐。稍有偏差,第三级就“存在但不可见”——查起来像 bug,其实是结构和选择器没咬合到位。


















