返回正文
Are you an LLM? You can read better optimized documentation at /zh-CN/blog/2025-10/web-animations.md for this page in Markdown format
Web Animation性能优化
🌟 前言
现代 Web 开发中,流畅的动画效果对用户体验至关重要。Web Animation API 提供了浏览器原生的 JavaScript 动画控制接口,相比传统方案,它提供更精细的控制、更优的性能和更强的组合能力。
Web Animation API 主要 API
| API | 描述 | 用途 |
|---|---|---|
Element.animate() | 创建并返回一个 Animation 对象 | 用于在元素上创建动画 |
| Animation | 动画对象的构造函数 | 表示单个动画实例 |
| KeyframeEffect | 关键帧效果对象的构造函数 | 定义动画的关键帧和效果 |
| AnimationTimeline | 动画时间线接口 | 管理动画的时间控制 |
| AnimationEffect | 动画效果接口 | 定义动画效果的基本结构 |
Document.getAnimations() | 获取文档中所有动画 | 返回文档中所有活动动画的数组 |
Animation.play() | 播放动画 | 启动动画播放 |
Animation.pause() | 暂停动画 | 暂停当前动画 |
Animation.reverse() | 反向播放动画 | 以相反方向播放动画 |
Animation.seek() | 跳转到指定时间点 | 设置动画播放位置 |
Animation.finish() | 完成动画 | 快速完成动画播放 |
Animation.cancel() | 取消动画 | 停止并取消动画 |
Animation.updatePlaybackRate() | 更新播放速率 | 改变动画播放速度 |
Animation.playbackRate | 获取或设置播放速率 | 控制动画播放速度 |
Animation.startTime | 获取或设置开始时间 | 控制动画开始时间 |
Animation.currentTime | 获取或设置当前时间 | 获取或设置动画当前位置 |
Animation.effect | 获取或设置动画效果 | 获取或设置动画效果对象 |
Animation.timing | 获取或设置动画计时 | 配置动画的计时属性 |
Animation.pending | 判断动画是否挂起 | 检查动画是否处于挂起状态 |
Animation.playState | 获取动画播放状态 | 获取动画当前状态 |
Animation.ready | 动画准备就绪的 Promise | 当动画准备好时触发 |
Animation.finished | 动画完成的 Promise | 当动画完成后触发 |
Animation.onfinish | 动画完成事件回调 | 处理动画完成事件 |
Animation.oncancel | 动画取消事件回调 | 处理动画取消事件 |
Animation.onremove | 动画移除事件回调 | 处理动画移除事件 |
🏗️ 一、核心概念解析
基础动画实现
ts
const element = document.getElementById('myElement');
// 基础动画示例
const animation = element.animate(
[
{ opacity: 0, transform: 'translateY(-50px)' },
{ opacity: 1, transform: 'translateY(0)' }
],
{
duration: 800, // 动画时长(ms)
easing: 'ease-out', // 缓动函数
fill: 'forwards' // 保持结束状态
}
);
// 播放动画
animation.play();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
关键帧序列详解
ts
// 多关键帧序列示例(包含偏移设置)
const complexAnimation = element.animate(
[
{ transform: 'scale(1)', backgroundColor: 'blue', offset: 0 },
{ transform: 'scale(1.5)', backgroundColor: 'purple', offset: 0.3 },
{ transform: 'scale(1.2)', backgroundColor: 'red', offset: 0.7 },
{ transform: 'scale(1)', backgroundColor: 'green', offset: 1 }
],
{
duration: 2000,
iterations: Infinity,
direction: 'alternate'
}
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
⚙️ 二、精细控制技术
动画控制函数
javascript
// 创建动画
const bounceAnimation = element.animate(
[{ transform: 'translateY(0)' }, { transform: 'translateY(-100px)' }],
{ duration: 1000 }
);
// 控制方法
const playBtn = document.getElementById('play');
playBtn.addEventListener('click', () => {
if (bounceAnimation.playState === 'paused') {
bounceAnimation.play();
} else {
bounceAnimation.pause();
}
});
// 跳转到特定时间点
document.getElementById('jump').addEventListener('click', () => {
bounceAnimation.currentTime = 300; // 跳转到300ms位置
});
// 速率控制
document.getElementById('speedUp').addEventListener('click', () => {
bounceAnimation.playbackRate *= 1.5; // 加速50%
});
// 结束后重置
bounceAnimation.onfinish = () => {
element.animate(
[{ transform: 'translateY(0)' }],
{ duration: 300, fill: 'forwards' }
);
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
动画事件监听
ts
const fadeInAnimation = element.animate(
[{ opacity: 0 }, { opacity: 1 }],
{ duration: 1500 }
);
// 事件监听
fadeInAnimation.onstart = () => {
console.log('动画开始');
};
fadeInAnimation.onfinish = () => {
console.log('动画完成');
element.textContent = '动画完成!';
};
fadeInAnimation.oncancel = () => {
console.warn('动画被取消');
};
fadeInAnimation.onremove = () => {
console.log('动画被移除');
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
🚀 三、高级动画技术
复合动画:序列执行
ts
// 动画1:平移
const moveRight = element.animate(
[
{ transform: 'translateX(0)' },
{ transform: 'translateX(200px)' }
],
{ duration: 1000 }
);
// 动画1结束后触发动画2
moveRight.onfinish = () => {
// 动画2:旋转
const rotate = element.animate(
[
{ transform: 'translateX(200px) rotate(0deg)' },
{ transform: 'translateX(200px) rotate(360deg)' }
],
{ duration: 800 }
);
// 动画2结束后触发动画3
rotate.onfinish = () => {
// 动画3:返回原点
element.animate(
[
{ transform: 'translateX(200px) rotate(360deg)' },
{ transform: 'translateX(0) rotate(0deg)' }
],
{ duration: 1200, easing: 'cubic-bezier(0.68, -0.55, 0.27, 1.55)' }
);
};
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
复合动画:并行执行
ts
// 同时执行多个动画
const parallelAnimations = [
element.animate(
[{ transform: 'scale(1)' }, { transform: 'scale(1.5)' }],
{ duration: 1500, easing: 'ease-in-out' }
),
element.animate(
[{ backgroundColor: '#3498db' }, { backgroundColor: '#e74c3c' }],
{ duration: 1500 }
),
element.animate(
[{ borderRadius: '0px' }, { borderRadius: '50%' }],
{ duration: 1500 }
)
];
// 监听所有动画完成
Promise.all(parallelAnimations.map(anim => anim.finished)).then(() => {
console.log('所有并行动画完成');
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
时间轴协调
ts
// 创建时间轴
const timeline = new DocumentTimeline();
// 动画A:移动
const moveAnim = element1.animate(
[{ transform: 'translateX(0)' }, { transform: 'translateX(200px)' }],
{
duration: 1000,
timeline // 指定时间轴
}
);
// 动画B:在动画A后立即开始(延迟1秒)
const colorChange = element2.animate(
[{ backgroundColor: 'blue' }, { backgroundColor: 'red' }],
{
duration: 1000,
timeline,
delay: 1000 // 1秒延迟
}
);
// 控制整个时间轴
const playTimeline = document.getElementById('playTimeline');
playTimeline.addEventListener('click', () => {
moveAnim.play();
colorChange.play();
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
路径跟随动画
ts
// 使用路径数据创建动画
const path = document.getElementById('motionPath');
const moveAlongPath = element.animate(
[
{ offsetDistance: 0, offsetPath: `path('${path.getAttribute('d')}')` },
{ offsetDistance: '100%' }
],
{
duration: 3000,
iterations: Infinity,
direction: 'alternate',
easing: 'ease-in-out'
}
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
📊 四、高级应用示例unsetunset
无限循环背景动画
javascript
function createBackgroundAnimation() {
const colors = ['#ff9ff3', '#feca57', '#ff6b6b', '#48dbfb', '#1dd1a1'];
const container = document.getElementById('bgContainer');
colors.forEach((color, i) => {
const dot = document.createElement('div');
dot.className = 'bg-dot';
dot.style.backgroundColor = color;
container.appendChild(dot);
// 对每个点创建随机动画
dot.animate(
[
{
transform: `translate(${Math.random() * 100}vw, ${Math.random() * 100}vh) scale(0)`
},
{
transform: `translate(${Math.random() * 100}vw, ${Math.random() * 100}vh) scale(1)`,
opacity: 0.7
}
],
{
duration: Math.random() * 5000 + 3000,
direction: 'alternate',
iterations: Infinity,
easing: 'cubic-bezier(0.445, 0.05, 0.55, 0.95)'
}
);
});
}
createBackgroundAnimation();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
物理效果弹跳动画
ts
const ball = document.getElementById('ball');
const ballAnimation = ball.animate(
[
{ transform: 'translateY(0)', easing: 'ease-in' },
{ transform: 'translateY(300px)', easing: 'ease-out', offset: 0.3 },
{ transform: 'translateY(100px)', easing: 'ease-in', offset: 0.5 },
{ transform: 'translateY(280px)', easing: 'ease-out', offset: 0.7 },
{ transform: 'translateY(150px)', easing: 'ease-in', offset: 0.8 },
{ transform: 'translateY(300px)', easing: 'ease-out' }
],
{
duration: 2000,
iterations: Infinity,
composite: 'add' // 与其他变换叠加
}
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3D 变换动画
ts
const cube = document.getElementById('cube');
// 创建3D旋转动画
cube.animate(
[
{
transform: 'rotateX(0deg) rotateY(0deg) rotateZ(0deg)',
filter: 'blur(0px)'
},
{
transform: 'rotateX(180deg) rotateY(180deg) rotateZ(0deg)',
filter: 'blur(2px)'
},
{
transform: 'rotateX(360deg) rotateY(360deg) rotateZ(180deg)',
filter: 'blur(0px)'
}
],
{
duration: 5000,
iterations: Infinity,
easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)'
}
);
// 添加透视效果
cube.parentElement.style.perspective = '1000px';1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
滚动驱动动画
ts
// 创建滚动驱动的时间轴
const scrollTimeline = new ScrollTimeline({
scrollSource: document.scrollingElement,
orientation: 'block',
timeRange: 1000
});
// 元素随着滚动变化
const scrollingElement = document.getElementById('scroll-element');
scrollingElement.animate(
[
{ opacity: 0, transform: 'scale(0.5)' },
{ opacity: 1, transform: 'scale(1)' }
],
{
duration: 1000,
timeline: scrollTimeline
}
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
🎯 五、性能优化技巧
GPU 加速最佳实践
css
// 使用 transform 和 opacity 属性可触发 GPU 加速
element.animate(
[ { transform: 'translate3d(0, 0, 0) scale(1)', opacity: 1 }, { transform: 'translate3d(100px, 100px, 0) scale(1.5)', opacity: 0.7 } ],
{ duration: 1000 }
);
// 避免触发重排的属性
// 推荐使用:transform, opacity, filter
// 尽量避免:width, height, padding, margin1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
高效动画组合
ts
// 使用 GroupEffect 进行复杂动画编排
const fadeIn = new KeyframeEffect(
element,
[{opacity:0}, {opacity:1}],
{duration: 1000}
);
const moveRight = new KeyframeEffect(
element,
[{transform:'translateX(0)'}, {transform:'translateX(200px)'}],
{duration: 1000}
);
// 串行动画
const sequence = new SequenceEffect([fadeIn, moveRight]);
// 并行动画
const parallel = new GroupEffect([fadeIn, moveRight]);
// 创建动画
const sequentialAnimation = new Animation(sequence, document.timeline);
const parallelAnimation = new Animation(parallel, document.timeline);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
✅ 六、完整示例
html
<!DOCTYPE html>
<html>
<head>
<style>
.box {
width: 100px;
height: 100px;
background: linear-gradient(135deg, #3498db, #9b59b6);
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
position: relative;
will-change: transform, opacity;
margin: 40px auto;
}
.ball {
width: 40px;
height: 40px;
position: absolute;
top: -60px;
left: calc(50% - 20px);
background: #e74c3c;
border-radius: 50%;
will-change: transform;
}
.controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
max-width: 600px;
margin: 20px auto;
}
button {
padding: 12px;
border: none;
background: #3498db;
color: white;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background: #2980b9;
}
button.pause {
background: #e67e22;
}
button.reset {
background: #e74c3c;
}
</style>
</head>
<body>
<div class="box" id="animatedBox">
Web Animations
<div class="ball" id="ball"></div>
</div>
<div class="controls">
<button id="play">播放</button>
<button id="pause" class="pause">暂停</button>
<button id="reverse">反向</button>
<button id="speedUp">加速</button>
<button id="slowDown">减速</button>
<button id="reset" class="reset">重置</button>
<button id="combo1">基础动效</button>
<button id="combo2">复杂动效</button>
<button id="combo3">弹跳小球</button>
</div>
<script>
const box = document.getElementById('animatedBox');
const ball = document.getElementById('ball');
// 创建基础动画
const boxAnimation = box.animate(
[
{ transform: 'rotate(0deg)', boxShadow: '0 0 0 rgba(0,0,0,0.1)' },
{ transform: 'rotate(360deg)', boxShadow: '0 10px 20px rgba(0,0,0,0.3)' }
],
{
duration: 2000,
iterations: Infinity,
easing: 'ease-in-out'
}
);
boxAnimation.pause();
// 创建小球弹跳动画
const ballAnimation = ball.animate(
[
{ transform: 'translateY(0)' },
{ transform: 'translateY(100px)', offset: 0.3 },
{ transform: 'translateY(30px)', offset: 0.6 },
{ transform: 'translateY(80px)', offset: 0.8 },
{ transform: 'translateY(60px)', offset: 0.9 },
{ transform: 'translateY(70px)', offset: 1 }
],
{
duration: 1000,
iterations: Infinity,
direction: 'alternate'
}
);
ballAnimation.pause();
// 控制函数
document.getElementById('play').addEventListener('click', () => {
boxAnimation.play();
ballAnimation.play();
});
document.getElementById('pause').addEventListener('click', () => {
boxAnimation.pause();
ballAnimation.pause();
});
document.getElementById('reverse').addEventListener('click', () => {
boxAnimation.playbackRate *= -1;
ballAnimation.playbackRate *= -1;
});
document.getElementById('speedUp').addEventListener('click', () => {
boxAnimation.playbackRate *= 1.5;
ballAnimation.playbackRate *= 1.5;
});
document.getElementById('slowDown').addEventListener('click', () => {
boxAnimation.playbackRate *= 0.75;
ballAnimation.playbackRate *= 0.75;
});
document.getElementById('reset').addEventListener('click', () => {
boxAnimation.cancel();
ballAnimation.cancel();
});
// 组合动画示例
document.getElementById('combo1').addEventListener('click', () => {
const colorAnimation = box.animate(
[
{background: 'linear-gradient(135deg, #3498db, #9b59b6)'},
{background: 'linear-gradient(135deg, #9b59b6, #e74c3c)'}
],
{duration: 1500, iterations: 2}
);
});
document.getElementById('combo3').addEventListener('click', () => {
// 创建小球路径动画
const moveBall = ball.animate(
[
{ transform: 'translateX(0)' },
{ transform: 'translateX(150px)' },
{ transform: 'translateX(0)' }
],
{
duration: 2000,
easing: 'ease-in-out',
iterations: Infinity
}
);
});
</script>
</body>
</html>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
本指南展示了 Web Animation API 的强大功能,通过掌握这些技术,您可以创建高性能、流畅的 Web 动画体验。
VN/A |
本站访客数
--次 本站总访问量
--人次 