先记住这个答案
animation-fill-mode 控制动画在两个特殊阶段的样式:延迟等待期间和动画结束之后。backwards 只管等待期间,让元素提前显示第一帧的样式;forwards 只管结束之后,让元素停在最后一帧;both 两个阶段都管;none 两个都不管,延迟期间保持元素原始样式,结束后也恢复回去。面试时最常考的就是 backwards 和 both 的区别,答案就一句话:等待期间两者一样,区别在结束后。
backwards管延迟期间,结束后恢复原样forwards管结束之后,延迟期间没效果both同时包含前后填充效果none延迟期间和结束后都不管
没有 animation-delay 时看不出 backwards 的效果
很多人写动画不加延迟,这时 backwards 几乎看不出作用,因为动画一开始就播放了。backwards 真正有用的场景是元素有一段等待时间。
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
/* none: 延迟期间 opacity 是元素默认值(1),动画开始突然跳到 0 再渐变到 1 */
.box-none {
animation: fade-in 1s ease 2s;
animation-fill-mode: none;
}
/* backwards: 延迟期间 opacity 就是 0,动画开始后平滑渐变到 1 */
.box-backwards {
animation: fade-in 1s ease 2s;
animation-fill-mode: backwards;
}
/* both: 延迟期间 opacity 是 0,结束后 opacity 保持 1 */
.box-both {
animation: fade-in 1s ease 2s;
animation-fill-mode: both;
}不加 backwards 或 both 的话,页面加载后元素会先以 opacity: 1 显示 2 秒,然后突然变成 opacity: 0 再渐入,用户会看到一次闪烁。加了 backwards,元素从一开始就是透明的,过渡很自然。
forwards 和 backwards 分别管哪一段
可以把动画的时间线分成三段:延迟期间、播放期间、结束之后。backwards 管第一段,forwards 管第三段,播放期间由 @keyframes 决定,和 fill-mode 无关。
forwards 让动画结束后保留最后一帧的样式。如果不设 forwards,动画结束后元素会跳回原始样式。比如做一个元素从左边滑入的动画,不设 forwards 的话播完元素会突然回到起始位置。
both 就是两个效果的叠加:延迟期间提前显示第一帧,结束后保留最后一帧。实际项目里用 both 最多,因为大部分时候你既不想让延迟期间闪烁,也不想让结束后跳回去。
animation-direction 会影响「第一帧」是哪一帧
backwards 应用的是「动画第一帧」的样式,但第一帧不总是 from。如果 animation-direction 设成 reverse,动画从 to 往 from 播,第一帧就是 to 对应的样式。同理,alternate 模式下奇数轮从 from 开始,偶数轮从 to 开始,backwards 应用的是第一轮的第一帧,也就是 from。
reverse 方向下 backwards 应用的是 to 的样式CSS@keyframes move {
from { transform: translateX(0); }
to { transform: translateX(200px); }
}
/* 反向播放,backwards 让延迟期间元素就在 200px 的位置 */
.box {
animation: move 1s ease 2s reverse;
animation-fill-mode: backwards;
}这个细节面试时容易答错。记住规则:backwards 应用的是动画真正开始那一帧的样式,方向变了,起始帧就变了。
容易答错的地方
- 以为
backwards和forwards的区别只是方向 - 不是方向的区别。
backwards管的是动画开始之前那段时间,forwards管的是动画结束之后那段时间。两者控制的是不同的时间阶段,不是动画播放的方向。 - 以为
both会改变动画的播放行为 both不影响动画播放过程本身,它只影响动画开始前和结束后元素的样式。播放过程中的关键帧插值、时间函数、方向,该怎么算还是怎么算。
面试官还会怎么问?
不写 animation-fill-mode 默认值是什么?
默认值是 none。延迟期间元素保持自身样式,动画结束后也恢复自身样式。这就是为什么很多动画结束后会「跳回去」。
forwards 保留的样式优先级有多高?
forwards 保留的样式和动画进行中的优先级一样,属于动画层叠层,优先级高于普通规则和 !important 以外的声明。如果后续用 JavaScript 修改了元素的 style,动画保留的值会被覆盖,但普通 CSS 类名加的样式覆盖不了。
无限循环的动画设 forwards 有意义吗?
没有实际意义。forwards 在动画结束后才生效,infinite 动画永远不会结束,所以 forwards 的效果永远不会出现。但 backwards 仍然有意义,它让延迟期间就显示第一帧。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。