animation-delay 必须严格等于前一个动画的 animation-duration 才能无缝衔接,差 0.01s 就会导致空档或重叠;多个动画需合并声明并按顺序配对所有属性,且必加 animation-fill-mode: forwards 固化终态。

animation-delay 必须和前一个动画 duration 严格对齐
很多人写 animation-delay: 0.3s 就以为能“接上”前一个动画,结果出现空档或重叠。这不是浏览器 bug,而是设计逻辑:delay 值必须等于前一个动画的 animation-duration,差 0.01s 都会翻车。
常见错误现象:
- 元素在第一段动画结束、第二段开始前“闪一下”或“跳一下”
- 两段位移动画衔接处有明显停顿感(实际是空档)
- 透明度+缩放同时启动,但缩放提前半拍,视觉错乱
实操建议:
- 统一用
s单位,避免混用ms导致计算误差 - 小数点后最多保留 2 位,如
0.25s;0.250s可能触发渲染引擎解析抖动 - 若前一个动画是
fade-in 0.4s,下一个必须设animation-delay: 0.4s,不能四舍五入成0.39s或0.41s
多个 animation 属性必须合并为单行逗号分隔
写两行 animation 声明是无效的——浏览器只认最后一行,前面的全丢弃。比如下面这段代码,只有 slide-up 生效:
立即学习“前端免费学习笔记(深入)”;
div {
animation: fade-in 0.3s;
animation: slide-up 0.4s 0.3s;
}正确做法是合并声明,并确保每个参数顺序一一对应:
div {
animation-name: fade-in, slide-up;
animation-duration: 0.3s, 0.4s;
animation-delay: 0s, 0.3s;
animation-fill-mode: forwards, forwards;
}注意点:
-
animation-timing-function、animation-iteration-count等也得按顺序配对,错一位整条链就失效 - 如果两个动画都改
transform,后启动的那个会覆盖前一个的终态,造成“闪回” - 动态 JS 插入的元素,必须确保 DOM 已挂载后再加 class,否则
animation-delay不触发
animation-fill-mode: forwards 几乎必加
没加 animation-fill-mode: forwards 是“闪一下才动”或“动完立刻弹回”的最常见原因。它不是可选项,而是链式动画的基础设施。
关键细节:
-
forwards只固化当前动画最后一帧,不会跨动画继承状态 - 如果第一个动画结束在
opacity: 0.8,第二个动画起始帧却是opacity: 1,那就会闪一下再变暗 - 多个动画共用同一属性(如都操作
transform),必须让后一个动画的0%关键帧显式承接前一个的100%状态 - 即使起始态和默认态一致(如都是
opacity: 1),仍建议显式写animation-fill-mode: backwards, forwards,避免逻辑断层
用 CSS 变量统一管理 delay 节奏更可靠
手算每个 animation-delay 值容易出错,尤其当动画步数多、时长不一时。推荐用变量驱动:
:root {
--anim-step: 0.25s;
}
.box:nth-child(1) { animation-delay: calc(var(--anim-step) * 0); }
.box:nth-child(2) { animation-delay: calc(var(--anim-step) * 1); }
.box:nth-child(3) { animation-delay: calc(var(--anim-step) * 2); }这样改节奏只要调一个变量,所有延迟自动同步。但要注意:
- JS 动态修改变量后,需触发重排(如读取
offsetHeight)或切换 class 才能刷新动画 - 变量不能直接用于
@keyframes内部,只适用于外部 delay 控制 - 若某步需要非等距延迟(比如第三步要等 0.8s 而不是 0.75s),单独覆盖即可,不影响整体结构
真正难的不是写对 delay,而是让每一帧的终态和下一帧的起点严丝合缝——这点调试时最容易被跳过,结果花半天调 timing-function,最后发现只是关键帧没对齐。


















