animation-direction: alternate 是唯一能实现循环+反向交替的原生方案,它使奇数轮正向(0%→100%)、偶数轮反向(100%→0%)自然衔接,需搭配 animation-iteration-count: infinite 等大于1的值,且避免与 forwards 冲突。

animation-direction: reverse 不能实现循环反向
直接设 animation-direction: reverse 只会让动画单次从 100% 倒播到 0%,它不循环,也不自动重置。哪怕你加了 animation-iteration-count: infinite,它也只是无限重复“从终点倒回起点”这一件事——视觉上就是卡在起始态不动,或来回闪跳。
真正要循环+反向,必须用 alternate
animation-direction: alternate 是唯一能同时满足「循环」和「每次正反交替」的原生方案。它不是“先正向播完再手动倒放”,而是把一次完整循环定义为:奇数轮(1、3、5…)走 @keyframes 正序(0% → 100%),偶数轮(2、4、6…)自动镜像为反序(100% → 0%),且每轮都从上一轮的终点自然衔接。
- 必须搭配
animation-iteration-count大于 1,比如infinite或2,否则看不出交替效果 - 缓动函数会自动镜像:如果正向用了
cubic-bezier(0.4, 0, 0.2, 1)(ease-in-out 类型),反向时浏览器会按时间轴翻转,等效于cubic-bezier(0.8, 0, 0.6, 1) - 关键帧首尾不必相同,但建议保持语义清晰:0% 是“初始态”,100% 是“目标态”,这样 alternate 才能正确映射往返逻辑
容易踩的坑:forwards + alternate 一起用会断层
如果同时写了 animation-fill-mode: forwards 和 animation-direction: alternate,第二轮反向开始前,元素会先跳回 0% 的样式——因为 forwards 把上一轮结束态(即 100%)锁住了,而 alternate 要求下一轮从 100% 开始倒播,但 DOM 状态却被强制拉回 0%,造成视觉跳变。
- 解决方案:去掉
forwards,改用backwards或both,或者干脆不设animation-fill-mode(默认none) - 更稳妥的做法是让动画本身自洽:比如用
transform: translateX()而非left,避免 layout 触发;关键帧只改合成属性,不碰盒模型
别用 JavaScript 监听 animationend 再切方向
有人想用 JS 在 animationend 事件里动态改 animation-direction 或重设 animation-name,这在实际中几乎必然失败:
- 事件触发时动画已结束,DOM 样式已固化,此时修改 CSS 属性会强制重排或重绘
- 浏览器无法保证 JS 修改与渲染帧同步,大概率出现半帧卡顿或状态错位
- 移动端尤其明显,低端设备上掉帧严重
真正需要 JS 干预的场景极少,比如要响应用户交互临时反转动画——这时推荐用 Web Animations API 的 reverse() 方法,它原生支持无缝倒播,且不依赖 CSS 声明顺序。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











