先记住这个答案
在延迟期间,backwards 和 both 都会将首个相关关键帧的样式应用到元素上,因此视觉上没有区别。区别在于结束后:backwards 会让元素回到未应用动画时的样式,而 both 会保留最后一个相关关键帧的样式。所以,如果只关心动画开始前的延迟表现,两者等价;但如果关心动画结束后的状态,必须用 both。
- 延迟期间两者均应用首帧样式,无差异
- 动画结束后 backwards 回退,both 保留末帧
- 注意 direction 会影响首帧和末帧的选取
- 只关心延迟期表现可任选,关心结局选 both
延迟期间填充样式的计算方式
动画的填充模式决定样式在动画执行外的应用范围。当 animation-delay 为正数时,元素在延迟期间尚未开始动画,此时 backwards 会让浏览器查找动画的第一个关键帧并作为样式源。这个首个关键帧由 animation-direction 决定:normal 或 alternate 使用 0%/from,reverse 或 alternate-reverse 使用 100%/to。both 完全继承了 backwards 的这一行为,因此在延迟期间两者的计算值完全一致。
需要区分的是“尚未开始时”的含义。如果 animation-delay 为负数,动画会立即从时间轴中某个点开始,不存在延迟期,此时 backwards 不生效。如果 delay 为0,也没有延迟窗口。只有在 delay > 0 时的等待阶段,backwards 与 both 的样式覆盖才可见。一旦动画开始,动画自身的关键帧会覆盖填充样式,所以延迟期只是填充模式的一个短暂窗口。
加载遮罩:延迟期间需要首帧入场形态
假设有个消息提示框,初始为不透明正放,动画定义从透明上移开始。需求是页面加载后等0.5秒再播放,且等待期间提示框应处于动画首帧的透明上移状态,避免突兀出现。设置 animation-delay: 0.5s; animation-fill-mode: backwards; 即可让遮罩在延迟期间显示首帧,动画结束后(假设只播放一次)回退到默认的不透明状态,正好符合遮罩消失逻辑。如果改用 both,结束后会停留在透明上移的最后一帧,导致遮罩永久消失,不符合要求。
这里的决策依据是:只要求动画开始前的填充,不要求动画结束后保持。backwards 精确控制了延迟期和结束后两个阶段,避免了额外的手动清除样式。若错误使用 both,可能还需要在动画结束后用 JavaScript 重置,增加复杂度。因此理解两者在延迟期的等价性,才能根据结束状态需求选择。
容易失效的条件与替代处理
backwards 与 both 在延迟期表现相同的前提是 animation-delay 明显大于零,且没有其他样式覆盖。如果元素自身有更高优先级的内联样式或 !important 规则,填充样式可能被覆盖,视觉上就看不出差异。另外,当动画有多个关键祯但首祯未定义属性时,该属性会从元素计算值推导,此时填充可能不会产生可见变化。
当动画使用 animation-fill-mode: both 但延迟期间元素被 display: none 或其他布局属性影响,填充样式可能不会在渲染树中生效。处理方式是确保动画属性是独立的可渲染值(如 opacity、transform),并检查层叠上下文。若需要模拟延迟期首帧,也可直接给元素设置初始样式,但这样会存在闪烁风险,不如用 backwards 由动画统一管理。代价是 backwards 在结束后回退会造成突变,需根据是否保留末帧决定是否改用 both。
容易答错的地方
- 认为两者在延迟期完全不同
- 一种常见误解是
backwards在延迟期不应用样式,只有both才应用。实际根据规范,backwards就是为延迟期设计的,它和both在延迟期都应用首帧,区别只在动画结束后的行为。 - 忽略了 direction 对首帧的影响
- 有人以为首帧永远是
from或0%,因此在reverse方向下设置backwards时会意外应用了100%的样式。需要根据animation-direction判断真正的第一相关关键帧,否则延迟期样式会错误。
面试官还会怎么问?
如果 animation-delay 为负值,backwards 和 both 会有何表现?
负延迟会使动画立即开始,从时间轴中某个点播放,此时没有“尚未开始”的延迟窗口,所以 backwards 不会产生额外首帧填充,元素直接进入动画当前帧。both 同样也不会应用首帧,因为动画已经在运行。
backwards 和 both 在动画结束后,对元素 z-index 或堆叠上下文的影响有何不同?
forwards 和 both 在动画结束后可能保留由动画属性创建的堆叠上下文,但 backwards 会回退,因此堆叠上下文也可能消失。具体取决于动画是否改变了 opacity 或 transform 等属性,backwards 不会保留这些效果。
在同一个元素上同时设置多个动画,且填充模式不同,延迟期如何应用?
每个动画的填充模式独立作用于各自的属性。延迟期间,具有 backwards 或 both 的动画会按顺序应用其首帧,若多个动画同时设置同一属性,优先级由 animation-* 的声明顺序和层叠决定,可能产生覆盖冲突。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。