真正起作用的是transition+可动画属性(如transform或max-height),且必须写在非hover的默认状态里;子菜单闪退或不可见主因是父级li未设position:relative导致定位断裂;需用display:none隐藏、精确选择器、避免:hover内写transition,并兼顾键盘与触控交互。

不能只靠 :hover 实现“平滑”,真正起作用的是 transition + 可动画属性(如 transform 或 max-height),且必须写在非 hover 的默认状态里。
为什么子菜单一 hover 就闪退或根本不出现在页面上?
最常见原因是定位上下文断裂:子菜单的直接父级 li 没设 position: relative,导致 position: absolute 的子菜单脱标到页面左上角,肉眼不可见。
- 每个带下拉的
li必须显式声明position: relative - 子菜单(如
.submenu)要用position: absolute; top: 100%; left: 0;定位,不能靠float或margin推位置 - 隐藏必须用
display: none,别用visibility: hidden或opacity: 0——它们会让鼠标“失焦”,:hover状态立刻中断 - 检查选择器链是否精确:
.main-menu > li:hover > .submenu才安全;写成.main-menu li:hover .submenu会污染其他层级
怎么加 transition 才有真正平滑的滑入滑出?
过渡动画必须定义在默认状态(非 hover),否则首次悬停是瞬时跳变,第二次才动。而且要选对可动画属性——display 不可过渡,height 会触发重排卡顿,transform 是首选。
- 给子菜单加
transition: transform 0.25s ease-out;,并在 hover 时用transform: translateY(0)拉回(初始设transform: translateY(-10px)或translateY(-100%)) - 如果坚持用
max-height过渡(兼容旧项目),初始设max-height: 0; overflow: hidden;,hover 时设为足够大的值(如max-height: 300px),但注意内容超长会截断 - 别在
:hover块里写transition,它只生效一次,且无法控制入场节奏
移动端和键盘用户怎么办?
:hover 在触控设备上天然不触发,纯 CSS 下拉菜单在手机上基本等于失效;键盘用户也无法用 Tab 键进入子菜单——这不是“优化问题”,是交互模型的根本缺陷。
- 不要指望
@media (hover: hover)能兜底,iOS Safari 和部分安卓浏览器对它的支持不稳定 - 若需真实可用,必须用 JavaScript 监听
focusin/blur补键盘逻辑,并用click或touchstart替代 hover 触发 - 用
aria-expanded和aria-haspopup标注状态,否则屏幕阅读器完全不知道子菜单存在
最易被忽略的一点:鼠标移向子菜单时的“物理空隙”。哪怕只有 1px,也会让 :hover 中断。解决方式不是加 delay(CSS 没可靠方案),而是用 padding-bottom: 2px 盖住父级 li 底部缝隙,再配 min-width: 100% 防子菜单过窄滑出——这是真正在生产环境里反复调出来的细节。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











