CSS 动画:animation、transition、transform、translate 傻傻分不清
Category(分类): CSS Status: 已整理
CSS 属性很多,有些属性无论是拼写还是字面意思都容易混淆。animation、transition、transform 和 translate 经常同时出现在动画代码中,但它们解决的问题并不相同。
| 属性 | 含义 |
|---|---|
animation | 根据 @keyframes 定义的关键帧和时间轴运行动画,支持循环、反向、暂停和延迟等能力 |
transition | 在属性的计算值发生变化时,让元素从起始值平滑过渡到结束值 |
transform | 对元素进行平移、旋转、缩放、倾斜等几何变换;它本身不是动画,但可以被 transition 或 animation 动画化 |
translate() | transform 中的平移变换函数,例如 transform: translate(20px, 10px) |
translate | 现代 CSS 中独立的变换属性,例如 translate: 20px 10px,不能简单理解为 transform 的属性值 |
先记住一句话:
transition和animation负责描述“如何随时间变化”;transform和translate负责描述“变化成什么样子”。
一、transition:过渡
1. 什么叫过渡?
过渡表示元素从某个计算值平滑地变化到另一个计算值。例如颜色从红色变为绿色:
.box {
color: red;
transition: color 0.3s ease;
}
.box:hover {
color: green;
}
transition 不会凭空播放动画,它需要属性的计算值发生变化。常见的变化来源包括:
:hover、:focus、:checked等伪类;- 类名变化;
- JavaScript 修改内联样式或 CSS 类;
- 媒体查询条件变化;
- CSS 自定义属性变化;
- DOM 状态变化。
下面是一个简单示例:
<div id="box"></div>
#box {
width: 100px;
height: 100px;
background: green;
transition: transform 1s ease-in 1s;
}
#box:hover {
transform: rotate(180deg) scale(0.5);
}
鼠标移入时,transform 从初始值变化为旋转并缩小后的值,触发过渡;鼠标移出时,transform 又变化回初始值,因此会再次执行过渡。

这里的 1s ease-in 1s 依次表示:
- 过渡持续时间:
1s; - 时间函数:
ease-in; - 延迟时间:
1s。
2. transition 的特点
transition 的特点是依赖属性值的变化:
- 仅声明
transition不会自动播放,必须先后存在可以比较的起始值和结束值; - 每次计算值再次发生变化时,都可以重复执行,并不是真正的“一次性动画”;
- 它通常只描述起始状态和结束状态,不能像
@keyframes那样显式定义多个时间节点; - 可以同时过渡多个属性,但每一条过渡记录仍然描述一个属性或属性集合;
- 页面首次加载时通常不会因为初始样式的应用而自动播放,需要在加载后改变状态才会触发。
例如,同时过渡多个属性:
.box {
color: #333;
background-color: #fff;
transform: translateX(0);
transition:
color 0.3s ease,
background-color 0.3s ease,
transform 0.3s ease;
}
.box:hover {
color: #fff;
background-color: #168bf5;
transform: translateX(20px);
}
也可以使用 all:
.box {
transition: all 0.3s ease;
}
但 all 可能让不希望动画化的属性也参与过渡,维护和性能控制不如明确列出属性。
3. transition 语法
.box {
transition: property duration timing-function delay;
}
更完整地说,transition 是以下长属性的简写:
| 长属性 | 描述 |
|---|---|
transition-property | 指定参与过渡的 CSS 属性,例如 color、transform 或 all |
transition-duration | 过渡完成所需的时间,单位通常为 s 或 ms |
transition-timing-function | 控制过渡过程中的速度曲线,例如 ease、linear、steps() |
transition-delay | 过渡开始前等待的时间,可以是负值 |
例如:
.box {
transition-property: opacity, transform;
transition-duration: 300ms, 500ms;
transition-timing-function: ease, ease-out;
transition-delay: 0ms, 100ms;
}
只有适合插值的属性才能产生连续过渡。颜色、长度、透明度和变换等属性通常适合过渡;某些离散属性只能在状态切换时直接改变。现代 CSS 也在逐步增加离散属性的过渡能力,但应结合目标浏览器支持情况使用。
二、animation:关键帧动画
1. animation 与 transition 的区别
animation 和 transition 都可以产生动画效果,但它们不是简单的包含关系,也不能把 animation 直接理解成多个 transition 的叠加。
transition依赖计算值变化;animation依赖@keyframes定义的时间轴;transition通常用于状态变化;animation可以在没有交互的情况下自动运行;animation支持关键帧、循环、反向、暂停和结束后的样式保留。
2. 一个 animation 示例
<div class="box"></div>
.box {
width: 100px;
height: 100px;
border: 15px solid #000;
animation: changebox 1s ease-in-out 1s infinite alternate;
}
.box:hover {
animation-play-state: paused;
}
@keyframes changebox {
10% {
background: red;
}
50% {
width: 80px;
}
70% {
border-color: yellow;
}
100% {
width: 180px;
height: 180px;
}
}
在这个示例中:
changebox是动画名称;1s是每次播放的持续时间;ease-in-out是时间函数;- 第二个
1s是延迟时间; infinite表示无限循环;alternate表示正向、反向交替播放;- 鼠标悬停时通过
animation-play-state: paused暂停动画。

3. @keyframes 的时间百分比
@keyframes 定义一个动画组合,例如:
@keyframes changebox {
0% {
transform: translateX(0);
}
50% {
transform: translateX(100px);
}
100% {
transform: translateX(0);
}
}
其中 0%、50% 和 100% 是动画有效时间轴上的位置。如果动画持续时间为 1s,50% 对应有效播放区间中的 0.5s,而不是包含延迟时间在内的总时间。
如果没有显式声明 0% 或 100%,浏览器会根据可用关键帧和元素动画前的样式推导起始或结束状态。关键帧之间的可动画属性会根据时间函数进行插值。
4. animation 语法
传统 animation 简写可以表示为:
.box {
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
}
它对应以下主要长属性:
| 长属性 | 描述 |
|---|---|
animation-name | 要使用的 @keyframes 名称 |
animation-duration | 每次播放的持续时间 |
animation-timing-function | 控制关键帧区间中的插值速度 |
animation-delay | 动画开始前的等待时间,可以是负值 |
animation-iteration-count | 播放次数,可以是具体次数或 infinite |
animation-direction | 播放方向,包括 normal、reverse、alternate 和 alternate-reverse |
animation-play-state | 播放状态,包括 running 和 paused |
animation-fill-mode | 动画执行前后是否应用关键帧样式 |
简写中的关键字顺序在一定范围内可以调整,但两个时间值中第一个通常解析为 duration,第二个解析为 delay。为了便于阅读,建议按照上面的顺序书写。
5. animation-direction
| 值 | 描述 |
|---|---|
normal | 每次按照关键帧声明的顺序播放 |
reverse | 每次按照关键帧声明的反方向播放 |
alternate | 奇数次正向、偶数次反向播放 |
alternate-reverse | 奇数次反向、偶数次正向播放 |
6. animation-fill-mode
| 值 | 描述 |
|---|---|
none | 动画执行前后不应用动画关键帧之外的保持效果 |
forwards | 动画结束后保留最后一个有效关键帧的样式 |
backwards | 在 delay 延迟期间应用第一个有效关键帧的样式 |
both | 同时应用 backwards 和 forwards 的效果 |
注意:forwards 只有在动画正常结束后才有明显效果。如果设置了:
animation-iteration-count: infinite;
动画不会正常结束,因此 forwards 没有实际的结束时机;但 backwards 仍可能在延迟期间生效。
负延迟可以让动画从时间轴中间开始:
.box {
animation-delay: -500ms;
}
这并不是先等待 500ms,而是表示动画开始时已经播放了一部分。
三、transform:变换
transform 用于改变元素的几何呈现方式,常见函数包括:
.box {
transform: translate(20px, 10px);
}
.box {
transform: rotate(45deg);
}
.box {
transform: scale(1.2);
}
.box {
transform: skewX(20deg);
}
多个变换函数可以组合:
.box {
transform: translateX(100px) rotate(45deg) scale(1.2);
}
变换函数的顺序会影响最终结果,平移后旋转和旋转后平移通常不是相同的结果,因此不要随意调换顺序。
transform 的重要特点
- 通常只改变元素的视觉呈现,不会按照变换后的尺寸重新排列普通流中的兄弟元素;
- 可能影响元素的命中测试区域和溢出区域;
transform不为none时通常会创建层叠上下文;- 可能成为绝对定位或固定定位后代的包含块;
- 经常用于位移、旋转、缩放动画,但不能因此绝对保证所有场景都具有更高性能;
- 默认情况下,变换围绕
transform-origin进行。
.box {
transform-origin: center;
transform: rotate(30deg);
}
如果只是让元素在页面中占据新的布局位置,应根据需求使用 margin、布局属性或定位,而不是一律使用 transform。
四、translate:平移
1. translate() 函数
translate() 是 transform 中的平移函数:
.box {
transform: translate(20px, 10px);
}
也可以使用:
.box {
transform: translateX(20px);
}
.box {
transform: translateY(10px);
}
.box {
transform: translateZ(20px);
}
2. 独立的 translate 属性
现代 CSS 还提供了独立的 translate 变换属性:
.box {
translate: 20px 10px;
}
它与下面的写法表达了相似的平移意图:
.box {
transform: translate(20px, 10px);
}
但二者属于不同的 CSS 属性体系。独立的 translate、rotate 和 scale 属性可以分别控制变换,适合需要独立修改某一个变换分量的场景。使用前应确认目标浏览器支持情况。
五、transition、animation、transform、translate 对比
| 项目 | transition | animation | transform | translate |
|---|---|---|---|---|
| 主要作用 | 在两个计算值之间过渡 | 按关键帧和时间轴播放 | 描述几何变换 | 描述平移变换 |
| 是否需要状态变化 | 通常需要 | 不一定需要 | 本身不负责播放 | 本身不负责播放 |
| 是否支持关键帧 | 不支持显式关键帧 | 支持 @keyframes | 不适用 | 不适用 |
| 是否支持循环 | 没有独立循环机制 | 支持 iteration-count | 不适用 | 不适用 |
| 是否可以暂停 | 没有专用播放状态 | 支持 animation-play-state | 不适用 | 不适用 |
| 是否能改变布局 | 通常不改变布局结构 | 取决于动画的属性 | 通常不改变普通流布局 | 通常不改变普通流布局 |
常见组合如下:
.button {
transform: translateY(0);
transition: transform 200ms ease;
}
.button:hover {
transform: translateY(-4px);
}
这里:
transform定义按钮要移动到哪里;transition定义移动过程如何变化;:hover提供计算值变化的触发条件。
另一个例子:
.loading {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
这里:
transform定义旋转变换;@keyframes定义从0deg到360deg的时间轴;animation让这个时间轴持续循环播放。
六、CSS 动画与 JavaScript 动画
CSS 动画适合声明式的状态变化和循环效果;JavaScript 适合根据用户输入、物理计算、游戏逻辑或实时数据动态控制动画。
不要使用 setTimeout 或 setInterval 简单地固定频率修改样式来代替所有动画。对于需要 JavaScript 驱动的视觉更新,通常可以使用 requestAnimationFrame:
let frameId
function render(timestamp) {
// 根据 timestamp 计算当前位置,并更新元素样式
frameId = requestAnimationFrame(render)
}
frameId = requestAnimationFrame(render)
// 需要停止时:
// cancelAnimationFrame(frameId)
requestAnimationFrame 通常会让回调与浏览器绘制节奏更协调,但它并不保证回调中的代码一定高性能。频繁读取布局、强制同步布局、复杂计算和大量 DOM 更新仍然可能造成卡顿。
如果只是实现简单的渐变、位移、旋转或循环效果,优先考虑 CSS transition 和 animation。
七、无障碍与性能注意事项
1. 尊重用户的减少动态效果设置
部分用户会在系统中启用减少动态效果。可以使用媒体查询降低或取消动画:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
具体项目也可以根据交互需求提供更合适的静态状态,而不是简单地让所有动画瞬间结束。
2. 选择适合动画的属性
位移、缩放、旋转和透明度经常适合做动画,但实际性能还与动画面积、设备、浏览器、阴影、滤镜和其他页面任务有关。不要仅凭属性名称绝对判断性能,应使用浏览器 Performance、Rendering 和 Layers 工具验证。
3. 避免无意义的 will-change
/* 不建议长期给大量元素设置 */
.box {
will-change: transform;
}
will-change 只是性能提示,过度使用可能增加内存占用和渲染管理成本。通常应在确实需要时短时间使用,或先通过性能工具确认问题。
总结
transition依赖计算值变化,在起始值和结束值之间产生过渡;transition可以同时处理多个属性,并不是只能处理一个属性;animation使用@keyframes和时间轴,可以自动播放、循环、反向和暂停;transform描述平移、旋转、缩放和倾斜等几何变换,本身不负责随时间播放;translate()是transform中的平移函数;translate也可以作为现代 CSS 的独立变换属性;transform通常不会让普通流兄弟元素重新布局,但可能影响层叠上下文和定位包含块;animation-fill-mode中正确的拼写是backwards;requestAnimationFrame适合 JavaScript 驱动的视觉更新,但不等于所有代码都会自动高性能;- 简单状态过渡优先使用
transition,复杂时间轴和循环效果优先使用animation; - 动画设计应考虑性能和
prefers-reduced-motion。