子菜单飘到页面左上角是因为position: absolute找不到已定位祖先,必须为每级含.sub-menu的li显式设position: relative,并避免overflow: hidden裁剪及hover间隙导致断连。

纯 CSS 实现多级菜单平滑展开,关键不在动画本身,而在定位结构是否稳固——position: absolute 找不到基准、overflow: hidden 裁掉子菜单、:hover 链断裂,这三个问题不解决,再好看的 transition 都白搭。
为什么子菜单总飘到页面左上角?
这不是浏览器 bug,是 position: absolute 的定位逻辑被忽略了:它只认「最近的已定位祖先」,不是直接父元素。如果父 <li> 没设 position: relative,它就一路往上找到 ,结果就是菜单贴着视口左上角弹出来。
- 所有含
.sub-menu的<li>必须显式加position: relative(不只是最外层<ul></ul>) - 用浏览器开发者工具检查「Computed」面板里的
offsetParent,确认定位上下文是否指向预期父级 - 千万别在父级上误加
overflow: hidden——它会直接裁掉position: absolute的子菜单,让内容“消失”
二级、三级菜单怎么避免层层打架?
继续对每层都套 position: absolute 是危险操作:z-index 层叠上下文分裂、transform 触发新层叠、响应式位移错乱都会接踵而至。
- 一级子菜单(
> ul)用position: absolute; top: 100%; left: 0,紧贴父项底部 - 二级及以上(
.sub-menu .sub-menu)改用position: relative; margin-left: 100%实现缩进和归属感 - 这样深层菜单随父容器自然位移,不依赖固定坐标;也无需为每层写独立选择器,靠后代选择器就能统一控制
- 如需 RTL 支持,把
margin-left换成margin-right即可
鼠标一移就闪退,怎么让 hover 连贯?
这不是 CSS 写错了,而是布局留了“缝隙”——鼠标从父项移到子菜单途中经过空白间隙,触发了 :hover 离开状态。
- 确保子菜单
top: 100%且margin: 0,与父项下边缘严丝合缝,不留任何像素空隙 - 父项设
position: relative,子菜单用left: 0对齐,防止因字体渲染或盒模型偏差导致偏移悬空 - 极简补救法:加一层连接桥选择器
.nav-list > li:hover > .sub-menu, .sub-menu:hover,但注意这会让键盘焦点行为变复杂,无障碍要求高的项目慎用
移动端点击展开后其他菜单不收起,纯 CSS 能解决吗?
不能。CSS 的 :hover 和 :focus-within 都无法实现“点击展开当前、收起其余”的互斥逻辑,必须靠 JavaScript 控制类名切换。
- 给所有可展开项统一加
data-toggle="dropdown",避免复用.submenu类名污染语义 - 用事件委托监听
click,精准查找目标元素的直接子级菜单(兼容.submenu和.nested-menu) - 点击外部区域时,用
document.querySelectorAll('.submenu, .nested-menu')统一收起,但要先排除菜单内部点击(e.target.closest('.main-menu'))
真正难的不是写动画,而是让每一级菜单都有自己的定位锚点、不互相干扰、不被裁剪、不因微小间隙中断交互——这些细节漏掉任意一个,用户看到的就是“闪退”“飘走”“点不开”,而不是“平滑展开”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











