先记住这个答案
alternate 让动画在正向与反向之间交替,第一轮正常从起始状态播放到结束状态,第二轮倒退,之后依此类推。reverse 则始终反向播放,即每一轮都从结束状态开始,按关键帧倒序执行,同时缓动函数也会被镜像,例如 ease-in 变为 ease-out。
- alternate 首轮正向,偶数轮反向
- reverse 始终反向,首轮即倒放
- 缓动函数在 reverse 中镜像
关键帧执行顺序与缓动镜像机制
关键帧动画的播放由 animation-direction 决定遍历 @keyframes 中百分比选择器的顺序。normal 按 0%、50%、100% 递增应用;reverse 从 100% 到 0% 递减,相当于把时间轴逆转。alternate 以迭代次数为参照:第一次迭代按 normal,第二次按 reverse,第三次再 normal,如此循环。
direction 为 reverse 时,不仅关键帧顺序倒置,timing-function 也会垂直镜像。例如 ease-in 曲线在倒放时表现为 ease-out,因为动画从终点向起点推进时,需要以与正向相同的加速度感觉。alternate 的反向轮次同理,会让正向缓动与反向缓动对称。
通知滑入滑出条的方向选择
场景:实现一个顶部通知条,进入时从上方 translateY(-100%) 滑入,持续 2 秒,随后希望它滑出。若设计为无限循环的进入/退出动画,选用 alternate 并配合 iteration-count: infinite 即可让元素自动来回;但如果需要先展示 2 秒再滑出且只播放一次,则可用两个动画或用事件控制,但核心判断是:alternate 会在第二次迭代反向,正好满足滑入后滑出。
但如果需求是“进入后从右侧滑出”,也就是两个不同方向的位移,则需要两个关键帧动画或改变起点,因为 alternate 的反向必然回到原始位置。相比之下 reverse 只改变播放方向,不会改变关键帧定义。正确做法:使用两个独立动画,或用 animation-direction: alternate 时令关键帧两端的 transform 形态都为 off-screen。
播放次数与动画填充模式带来的干扰
当 iteration-count 不是整数时,alternate 会在某次只播放部分周期。例如 2.5 次迭代,第一次正向完整,第二次反向完整,第三次只正向播放一半,停在 50% 进度处。reverse 则每轮都从结束状态开始,第 0.5 轮时实际相当于播放到中间进度。要求精确停在某个关键帧位置时,必须用 CSS 变量或 JS 额外计算。
animation-fill-mode 会影响动画非运行阶段的样式。若使用 both 或 backwards,在 delay 期间会应用第一个关键帧样式;对 reverse 来说,第一个关键帧是 @keyframes 中定义的最后一个(100%)。若误以为 fill-mode 会保留结束样式,可能与方向组合混淆。建议在调试时同时明确 direction 和 fill-mode。
容易答错的地方
- 把 reverse 当成仅在偶数轮反向
- 有观点认为 reverse 是第二遍播放时反向。实际 reverse 从第一轮起就反向播放,每一轮都从结束状态开始,与 alternation 的奇偶切换完全不同。
- 忽视 alternate 首轮仍正向
- 有人把 alternate 理解成第一轮就反向。实际上 alternate 以正常方向开始,只有当迭代次数达到第二轮才反向,而 alternate-reverse 才以反方向开头。
面试官还会怎么问?
animation-direction: alternate 与 alternate-reverse 在播放次数上的差异是什么?
两者都会交替方向,差异只在第一轮方向:alternate 首轮正向,alternate-reverse 首轮反向。当次数为奇数时,最终停在正向终点;为偶数时停在反向终点。
如果 keyframes 中只定义了 0% 和 100%,reverse 是否等同于交换 from/to?
是,但 reverse 不需要修改 @keyframes,同时自动反转移 ease 函数。交换 from/to 后方向相同,但缓动曲线不会自动镜像,需要手动更换等价的曲线。
动画暂停后修改 animation-direction 会立即生效吗?
会,但视觉效果取决于修改时的当前进度。例如在正向播放到 30% 时改为 reverse,动画会从当前时间点开始倒退,但进度条时间线不是简单翻转,可能产生跳跃,需要结合 animation-play-state 谨慎使用。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。