纯css无法自动计算nth-child动画delay,必须用js注入--i变量:item.style.setproperty('--i', index + 1),再通过animation-delay: calc(var(--i) * 0.1s)实现;注意safari要求小数必须写全0.1s而非.1s,且避免height:0→auto等非法动画。

nth-child 动画 delay 值怎么算才不手抖
直接给公式:animation-delay: calc(var(--i) * 0.1s),但 CSS 里 var(--i) 不能直接递增——nth-child 本身不提供索引变量,必须靠预设或 JS 注入。纯 CSS 方案只能手动写死每个项的 delay,比如 :nth-child(1) 延迟 0s,:nth-child(2) 延迟 0.1s……写到第 20 项就容易漏、错、晕。
常见错误现象::nth-child(n) 被误当成“自动遍历”,结果只生效第一个;或者用 ~ 选择器试图批量控制,发现根本没反应。
- 真正能用的只有
:nth-child(1)、:nth-child(2)这种具体数字形式 - 如果列表长度不确定(比如后端渲染、动态增删),纯 CSS 几乎无法可靠实现逐条滑入
- 浏览器对大量
:nth-child(n)规则的解析开销会上升,尤其在低配设备上可能卡顿
用 CSS 自定义属性 + JS 注入索引更稳
让 JS 给每个 li 元素打上 style="--i: 1"、style="--i: 2" 这样的内联样式,CSS 再用 calc() 算 delay。这样既保持动画声明在 CSS 里,又避开硬编码限制。
使用场景:Vue/React 列表渲染前、或原生 document.querySelectorAll('li') 遍历后。
立即学习“前端免费学习笔记(深入)”;
- JS 部分只需一行:
item.style.setProperty('--i', index + 1) - CSS 动画写成
animation: slideIn 0.4s ease-out forwards;,再单独定义@keyframes slideIn { from { opacity: 0; transform: translateY(10px); } } - delay 必须写在触发动画的规则里,比如
li { animation-delay: calc(var(--i) * 0.15s); },不能塞进@keyframes
transition 和 animation 混用会互相覆盖
如果你的列表项原本有 hover 缩放、颜色过渡等 transition,而新加了 animation,注意:animation 的 transform 和 opacity 会完全接管对应属性,导致 hover 效果失效或跳变。
性能影响:同时跑多个 transform 动画(比如入场 + hover 缩放)在低端 Android 上容易掉帧。
- 解决办法是统一收口到 animation,把 hover 效果也写成 keyframes 片段,用
animation-play-state控制暂停/恢复 - 或者干脆放弃 hover 的 transform,改用
background-color或box-shadow这类廉价属性做反馈 - 别在
animation里写height: 0 → auto,这个值无法动画,会直接跳变
移动端 Safari 对 calc() 里的单位敏感
在 iOS 15.4 之前,calc(var(--i) * 0.1s) 中的 0.1s 如果写成 .1s(省略前导零),Safari 会忽略整个 delay 声明,所有项同时入场。
兼容性影响:不是 bug,是规范要求——CSS 数值中带小数点的必须有整数位,.1 是非法 token。
- 务必写成
0.1s、0.15s,不能简写 - 如果用 CSS-in-JS 库(如 Emotion),检查它是否自动补零;有些模板字符串拼接会丢掉前导零
- 真机调试时,用 Safari 开发者工具的“Computed”面板看
animation-delay是否解析为有效值,而不是invalid value
最麻烦的其实是列表项高度不一致时的布局抖动——滑入过程中其他项会被顶着上下跳,这得靠 contain: layout 或提前占位来压住,但那是另一个问题了。










