可行但需配合 animation-fill-mode: backwards,否则元素会先闪现再动画;JS 动态设 animationDelay 更灵活;注意移动端兼容性及触发时机。

直接用 animation-delay 实现列表项逐个淡入是可行的,但必须配合 animation-fill-mode: backwards,否则第一帧会直接显示内容,动画“闪一下”就没了。
为什么 animation-delay 单独用会失效
只设 animation-delay 不加 animation-fill-mode: backwards,浏览器默认在动画开始前不应用任何关键帧样式(比如 opacity: 0),导致元素一渲染就可见,延迟后才执行淡出→淡入,视觉上就是“先闪现再重播”。
-
animation-fill-mode: backwards强制让动画的起始状态(@keyframes中的0%)在动画真正开始前就生效 - 必须搭配
opacity: 0的初始状态(不能只靠 CSS 动画内部定义) - 若用
visibility: hidden替代opacity,会导致布局塌陷,不推荐
如何动态生成 delay 值(适配不同长度列表)
硬写死每个 li:nth-child(1) { animation-delay: 0s; } 到 :nth-child(10) 不现实。更可靠的方式是用 JS 遍历并设置内联 style:
document.querySelectorAll('.item').forEach((el, i) => {
el.style.animationDelay = `${i * 0.15}s`;
});
- 延迟步长建议控制在
0.1s–0.2s之间:太短看不出递进,太长用户等待感强 - 避免用
setTimeout每项单独触发,会增加 JS 执行负担,且无法和 CSS 动画自然衔接 - 如果列表由框架(如 Vue/React)渲染,应在
mounted或useEffect中批量设置,而非每次setState都重算
移动端性能与兼容性注意点
在 iOS Safari 和部分安卓 WebView 中,animation-delay + backwards 组合偶有渲染异常,尤其配合 transform 时。
- 务必为动画元素添加
will-change: opacity或transform,触发硬件加速,减少闪屏 - 避免同时对大量项(>50)启用该动画;可结合
IntersectionObserver,只对进入视口的项启动延迟动画 - 旧版 Android Webview(≤4.4)不支持
animation-fill-mode: backwards,需降级为 JS 控制opacity+transition - 不要用
margin-top或height做入场动画——触发布局重排,卡顿明显
真正容易被忽略的是:动画触发时机。很多页面在 DOM 渲染完成前就设置了 animation-delay,结果首项 delay 为 0s 的动画已跑完,后续项才陆续开始。确保所有列表项已挂载、样式已计算完毕再统一启用动画类名或内联 style。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











