transition-delay在多级菜单中常失效,因不继承且需子菜单已渲染可见;须用visibility+opacity替代display:none,各级独立设delay(如0s/0.1s/0.2s),并注意safari等兼容性问题。

transition-delay 在多级菜单里为什么经常失效
因为 transition-delay 不会“继承”或“自动累加”,子菜单的延时必须显式设置,且依赖父元素是否已触发重排或动画状态。常见错误是只给 .submenu 加 transition-delay: 0.1s,但父菜单展开时子菜单还没被插入 DOM 或仍为 display: none —— 此时 CSS 动画压根不会启动。
真正起作用的前提是:子菜单元素必须已渲染、可见(至少 opacity: 0 + visibility: visible)、且有可过渡的属性变化。
- 用
display: none切换会导致 transition 中断,改用visibility+opacity组合 - 每级菜单需独立设置
transition-delay,比如一级延迟 0s,二级 0.1s,三级 0.2s - 延迟值建议用
ms单位(如0.15s),避免小数点后过多位导致浏览器解析不一致
如何用 CSS 实现三级菜单逐级淡入(无 JS)
核心是利用父子关系和 CSS 层叠顺序,靠 :hover 触发链式显示,并为每层 opacity 设置不同 transition-delay。
示例结构:
立即学习“前端免费学习笔记(深入)”;
<nav>
<ul class="menu">
<li><a href="#">首页</a></li>
<li class="has-sub">
<a href="#">产品</a>
<ul class="submenu">
<li class="has-sub">
<a href="#">Web 端</a>
<ul class="submenu">
<li><a href="#">React 版</a></li>
<li><a href="#">Vue 版</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
对应关键 CSS:
-
.submenu初始设为opacity: 0; visibility: hidden;,并定义transition: opacity 0.2s ease, visibility 0.2s - 一级子菜单:
.menu > li:hover .submenu { opacity: 1; visibility: visible; } - 二级子菜单:
.submenu > li:hover .submenu { opacity: 1; visibility: visible; transition-delay: 0.1s; } - 三级子菜单:
.submenu .submenu > li:hover .submenu { transition-delay: 0.2s; }
transition-delay 和 hover 一起用的兼容性坑
在 Safari(尤其是 iOS 15–16)和旧版 Edge 中,:hover 链式触发 + 多层 transition-delay 容易出现“跳过中间级”或“延迟不生效”的问题,根本原因是浏览器对嵌套伪类重绘的优化策略不同。
- 不要依赖
.submenu:hover .submenu,改用.has-sub:hover .submenu(给有子菜单的<li>加类) - 避免在
:hover中同时修改display和opacity,否则 Chrome 可能跳过 transition - 移动端没有
:hover,必须配合@media (hover: hover)做降级处理,否则纯触屏设备菜单打不开
用 JS 补足 CSS 做不到的部分
CSS 能控延迟和淡入,但没法解决“鼠标快速划过时菜单闪退”或“点击收起时反向淡出”。这时候得用 JS 控制 class 的增删时机,而不是依赖纯 hover。
- 监听
mouseenter后用setTimeout延迟添加is-open类,避免误触 - 用
getComputedStyle(el).opacity判断当前是否处于动画中,防止重复触发 - 收起时手动加
is-closing类,CSS 中写.is-closing { opacity: 0 !important; },再用transitionend移除元素
最麻烦的不是怎么写,而是各级 delay 值得反复调——0.05s 差太多,0.15s 又太拖沓,实际项目里建议从 0.1s 起调,配合真实鼠标移动速度测试。










