animation 与 transition 本质不同:transition 是状态间补间,仅支持两态切换;animation 是时间轴驱动序列,支持多关键帧、循环、方向控制等。必须用 animation 的场景包括:多属性异步变化、中间停顿、非线性路径、反向循环、独立延迟启动。@keyframes 不支持 auto/inherit/calc() 等动态值,且 timing-function 无法逐帧设置,复杂效果需组合多个 animation 实现。

animation 和 transition 本质不是替代关系
它们解决的问题层级不同:transition 是状态切换的“补间”,只在属性值变化时触发,且只能定义起始、结束两个状态;animation 是时间轴驱动的“序列”,通过 @keyframes 显式控制每一帧,支持多关键帧、循环、方向控制等。
什么时候必须用 animation 而不能靠 transition
当你需要以下任一能力时,transition 就无能为力:
- 同一动画中改变多个属性,且变化节奏不一致(比如 opacity 淡入快、transform 平移慢)
- 中间停顿、回弹、跳跃(例如:0% → 50% → 100%,其中 50% 处停留 0.3s)
- 非线性路径运动(如贝塞尔曲线轨迹、绕圆旋转 + 缩放)
- 循环次数大于 1 且需反向播放(
animation-iteration-count: 3; animation-direction: alternate;) - 动画开始前有延迟,但延迟后不希望立即执行第一帧(
animation-delay可独立于触发时机)
@keyframes 里不能写 auto、inherit 或 calc() 动态值
@keyframes 中所有属性值必须是可计算的静态值。常见踩坑点:
-
left: auto无效 —— 改用具体像素或百分比(如left: 0或left: 100%) -
width: inherit不被解析 —— 需提前知道目标宽度,或改用 JS 配合getComputedStyle注入变量 -
transform: translateX(calc(100vw - 100px))在 keyframes 中不生效 ——calc()只在声明块顶层有效,keyframes 内需预计算为固定值 - 百分比基准是元素自身尺寸,不是父容器 —— 如
top: 50%是相对于自身 height 的 50%,不是父元素
animation-timing-function 对整个序列生效,无法逐帧设置
animation-timing-function(如 cubic-bezier(.2, .8, .4, 1))作用于整个动画周期,从 0% 到 100% 的整体插值方式。它不能像 SVG 的 animate 那样给每一段 keyframe 单独设缓动。
立即学习“前端免费学习笔记(深入)”;
如果需要分段不同缓动,只能拆成多个 animation:
@keyframes slide-in {
0% { transform: translateX(-100%); }
100% { transform: translateX(0); }
}
@keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(-20px); }
100% { transform: translateY(0); }
}
.element {
animation: slide-in 0.6s cubic-bezier(.2, .8, .4, 1),
bounce 0.4s 0.6s ease-out;
}注意第二段动画的 0.6s 延迟,就是靠这个实现“滑入完成后再弹跳”。这种组合才是真实项目里写复杂效果的常规做法。
真正难的不是写多少帧,而是理清各段动画的时间对齐点、是否依赖 DOM 尺寸、是否要响应用户交互中断 —— 这些没法靠 animation 属性自动处理。










