鼠标划过菜单收起是因transition-delay未区分入场/退场:需用:not(:hover)为退场单独设延迟,并配合visibility: hidden禁用交互,避免误点;多级菜单须手动倒序设置各级退出延迟。

鼠标一划就收,不是bug,是transition-delay没配对退出逻辑。 只给入场加延迟,退场就会“立刻消失”,用户根本来不及点子菜单。真正要控制的是:hover结束后的那一段延迟——它必须独立设置,且方向相反。
transition-delay只作用于状态切换瞬间,不区分入场/退场
CSS 的 transition-delay 是个“启动等待器”:只要元素的过渡属性值变了(比如 opacity 从 1→0 或 0→1),它就等那么久再开始动画。浏览器不会自动区分这是 hover 进入还是离开。
常见错误写法:.submenu { transition: opacity 0.2s ease 0.15s; } —— 这会导致鼠标刚移入就等 0.15s 才淡入,移出也等 0.15s 才淡出,体验卡顿又不可控。
正确做法是把延迟只绑在“退场”路径上:
- 默认状态(收起)设
opacity: 0; visibility: hidden;,并配完整 transition:transition: opacity 0.2s ease, visibility 0.2s ease; - :hover 状态(展开)只改
opacity: 1; visibility: visible;,不加 delay - 退场延迟靠
transition-delay写在隐藏态规则里,例如:.nav-item:not(:hover) .submenu { transition-delay: 0.15s; }
防止误切的关键:用:not(:hover) + visibility 组合
仅靠 opacity 淡出,鼠标在延迟期内划过菜单区域仍可点击——因为元素还在文档流里、只是透明。必须配合 visibility: hidden 才能真正“禁用交互”,但它本身不可过渡,所以得和 opacity 联动。
实操要点:
- 别写
.submenu { opacity: 0; transition-delay: 0.15s; }—— 这会连入场也拖慢 - 改用:
.nav-item:not(:hover) .submenu { opacity: 0; visibility: hidden; transition-delay: 0.15s; } - 确保父容器(如
.nav-item)有足够 hover 触发区,留 4–8px 垂直间隙,避免鼠标移出时断连 - 移动端必须 fallback:iOS Safari 对
:not(:hover)支持不稳定,需 JS 监听touchstart并加临时类
多级嵌套时,每层 transition-delay 必须显式倒序
二级菜单收起要晚于一级,三级要晚于二级——但 transition-delay 不继承,也不按 DOM 深度自动累加。你得手动给每级设不同值,且退出时要“反向触发”:视觉上最后出现的,延迟最短,最先收。
例如三级菜单结构:
- 一级
.menu-item→ 展开.submenu-1,退出延迟0.3s - 二级
.submenu-1 .menu-item→ 展开.submenu-2,退出延迟0.2s - 三级
.submenu-2 .menu-item→ 展开.submenu-3,退出延迟0s
对应 CSS:
.menu-item:not(:hover) .submenu-1 { opacity: 0; visibility: hidden; transition-delay: 0.3s; }
.submenu-1 .menu-item:not(:hover) .submenu-2 { opacity: 0; visibility: hidden; transition-delay: 0.2s; }
.submenu-2 .menu-item:not(:hover) .submenu-3 { opacity: 0; visibility: hidden; transition-delay: 0s; }
最麻烦的从来不是写几行 CSS,而是 Safari 在 visibility: hidden 元素上对 transition-delay 的解析有时会跳过,尤其当父级用了 transform: translateZ(0)。真机测试前,先关掉硬件加速看效果是否一致。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











