纯CSS多级下拉菜单桌面端可行但需满足三条件:父级li显式设position:relative、子菜单用display:none/block切换、:hover选择器链完整嵌套;移动端不可靠,必须改用checkbox或JS触发。

纯 CSS 实现多级下拉菜单,桌面端可行,移动端必须配合 JavaScript 或 checkbox 切换逻辑——仅靠 :hover 在触屏设备上完全不可靠。
position: relative 必须显式加在每一级父 li 上
子菜单用 position: absolute 时,浏览器会向上查找最近的定位上下文(relative/absolute/fixed)。如果 ul.nav > li 没设 position: relative,它就可能相对于 body 定位,导致二级菜单飘到页面左上角。
-
ul.nav > li和所有带子菜单的li.has-submenu都要加position: relative - Flex 布局不会自动创建定位上下文,
display: flex的容器里仍需手动加relative - 不要依赖
html或body作为定位根——它们默认不是定位元素
:hover 触发只适用于桌面,移动端得换触发方式
触屏设备没有持续的 hover 状态,手指移开即失焦,:hover 无法维持二级菜单显示。纯 CSS 方案在移动端只能退化为「点击展开」,需借助 <input type="checkbox"> 或 JavaScript。
- 桌面端可用
li:hover .submenu控制显示 - 移动端建议用
input[type="checkbox"] + label + ul结构,靠:checked控制.submenu的max-height或visibility - 避免在移动端同时监听
:hover和:active——行为不一致,容易闪退
消除悬停断点:二级菜单必须紧贴一级项底部
鼠标从一级项移到二级菜单时,如果两者之间有空隙,:hover 状态会中断,造成菜单“一闪而过”。
立即学习“前端免费学习笔记(深入)”;
- 给二级
.submenu设top: 100%,让它紧贴父li底边 - 加
margin-top: -1px或padding-bottom: 2px消除视觉间隙 - 确保父
li的line-height和padding不意外撑开间隙
z-index 不是越多越好,只在必要层级设
盲目给所有菜单加 z-index: 999 会导致层叠顺序混乱,比如三级菜单盖不住模态框,或被隔壁组件遮挡。
- 一级菜单设
z-index: 100,二级z-index: 101,三级z-index: 102即可 - 只在发生遮挡时才调整,优先检查父容器是否设置了
overflow: hidden或transform——这两者会创建新的层叠上下文,让z-index失效 - 避免跨组件全局设高
z-index,否则后期维护成本陡增
最易被忽略的是定位上下文链和移动端触发机制——很多人调通了桌面效果就以为完成了,结果在 iPad 上点一下菜单就收回去,根本没法操作三级项。


















