纯CSS二级下拉菜单在桌面端可行,但需满足三条件:父级li设position:relative、子菜单用display:none/block切换、:hover选择器链完整嵌套;移动端因无持续hover状态,仅靠:hover不可靠。

纯 CSS 实现二级下拉导航在桌面端完全可行,但必须满足三个硬性条件:父级 li 显式设 position: relative、子菜单用 display: none/block 切换、:hover 选择器链完整嵌套;移动端则无法仅靠 :hover 可靠工作。
为什么鼠标一移开菜单就消失了?
这不是 bug,是 :hover 的自然行为——它只作用于当前悬停的元素。一旦鼠标离开 li 或 a,又没碰到二级 ul,整个链路就断了。
-
ul必须是li的直接子元素(不能隔层,比如li > div > ul) -
li必须有position: relative,否则ul会相对于body定位,且悬停态无法“传递”过去 -
ul用position: absolute+top: 100%紧贴父li底边,间隙哪怕 1px 都会导致mouseout - 避免给
li设line-height或padding-bottom撑开空隙;必要时加margin-top: -1px补偿边框
移动端点一下就收起,怎么破?
触屏设备没有持续 hover 状态,手指抬起来即失焦,:hover 在 iOS Safari 和 Android Chrome 上都不可靠。纯 CSS 方案在这里必须降级。
- 不要尝试用
:active或:focus模拟——行为不一致,容易闪退或卡死 - 推荐用
input[type="checkbox"]+label结构:label点击触发input:checked,再用:checked ~ .submenu控制显示 - 如果已用 Bootstrap 5,默认启用了 Popper.js,二级
ul可能被重定位;加data-bs-popper="none"到该ul上禁用自动计算 - iOS Safari 对
:focus-within支持有限,别依赖它做核心逻辑
z-index 和定位上下文常被忽略
菜单盖不住模态框、三级菜单飘到左上角……这些问题八成出在定位上下文或层叠顺序上。
立即学习“前端免费学习笔记(深入)”;
-
z-index只对「已定位元素」生效(即position是relative/absolute/fixed/sticky);光设z-index不设position是无效的 - 父容器若含
overflow: hidden或transform,会创建新层叠上下文,导致子元素的z-index相对父级生效,而非全局 - 一级菜单设
z-index: 100,二级101,三级102足够;盲目堆高值(如9999)反而让后期调试更难 - Flex 容器不会自动创建定位上下文——即使
ul是display: flex,其子li仍需手动加position: relative
最易踩的坑不在写法本身,而在测试阶段只跑桌面 Chrome 就上线。iPad 上点开二级菜单后手指一松就收起,用户根本点不到第三级——这种问题必须在真机触屏环境下验证,不能靠模拟器或 hover 开关代替。


















