JavaScript 动画终极教程
动画的本质是在短时间内连续改变元素的视觉属性(如位置、大小、颜色、透明度等),利用人眼的视觉暂留效应,使其看起来平滑地运动起来。

我们将从最核心的概念开始,逐步深入到现代、高性能的动画技术。
第一部分:基础篇 - setInterval 与 setTimeout
这是最传统、最直观的动画实现方式。
核心思想
通过 setInterval 或 setTimeout 在一个固定的时间间隔(例如每 16ms,约等于 60fps)内,重复地更新元素的样式,从而产生动画效果。
setInterval 方法
setInterval 会每隔指定的时间执行一次函数,非常适合创建循环动画。

示例:一个简单的方块移动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">JS Animation - setInterval</title>
<style>
#box {
width: 50px;
height: 50px;
background-color: blue;
position: absolute; /* 必须是定位元素才能改变 top/left */
top: 0;
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let position = 0;
const speed = 2; // 每次移动的像素
// 使用 setInterval 创建动画循环
const animationInterval = setInterval(() => {
// 更新位置
position += speed;
// 应用新的位置
box.style.left = position + 'px';
// 如果方块移出视口,停止动画
if (position > window.innerWidth) {
clearInterval(animationInterval); // 清除定时器
}
}, 16); // 大约 60fps (1000ms / 60 ≈ 16.7ms)
</script>
</body>
</html>
优点:
- 简单易懂,适合初学者理解动画的基本原理。
缺点:
- 性能不佳:
setInterval是独立于浏览器渲染循环的,它不管浏览器是否在重绘页面,都会执行,这可能导致掉帧,动画卡顿。 - 不精确:JavaScript 主线程被其他任务阻塞,
setInterval的回调可能会被延迟执行,导致动画时间不准确。 - 难以控制:暂停、恢复、反向等操作比较繁琐。
第二部分:进阶篇 - requestAnimationFrame
这是现代浏览器提供的专业动画 API,是制作网页动画的标准方式。

核心思想
requestAnimationFrame 会告诉浏览器:“我想要在下一次重绘之前执行一个动画,请为我安排这个更新。” 它与浏览器的刷新率(通常是 60fps)同步,确保动画只在需要的时候更新,并且不会造成不必要的性能开销。
requestAnimationFrame 方法
示例:使用 requestAnimationFrame 实现方块移动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">JS Animation - requestAnimationFrame</title>
<style>
#box {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
top: 50px; /* 从顶部50px开始 */
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
let position = 0;
const speed = 2;
let animationId; // 用于存储 requestAnimationFrame 的 ID
// 动画循环函数
function animate() {
// 更新位置
position += speed;
box.style.left = position + 'px';
// 如果方块还在视口内,继续请求下一帧
if (position < window.innerWidth) {
// 这是关键:递归调用,形成循环
animationId = requestAnimationFrame(animate);
} else {
// 如果移出视口,停止动画
cancelAnimationFrame(animationId); // 取消动画
}
}
// 启动动画
animate();
// 如果需要暂停动画,可以调用 cancelAnimationFrame(animationId);
// 如果需要恢复,再次调用 animate();
</script>
</body>
</html>
优点:
- 高性能:与浏览器渲染周期同步,自动优化,减少不必要的计算和绘制,动画更流畅。
- 省电:当浏览器标签页处于非活动状态时,
requestAnimationFrame会自动暂停,从而节省电量。 - 更流畅:提供更精确的动画控制,避免卡顿。
- 易于控制:只需一个
cancelAnimationFrame就能轻松停止动画。
缺点:
- 对于非常简单的动画,代码量比
setInterval稍多。
第三部分:现代动画库 - GSAP (GreenSock Animation Platform)
当动画变得复杂(如多个元素、时间轴、缓动效果、物理效果等),手动编写 requestAnimationFrame 会变得非常困难,这时,专业的动画库是更好的选择。
GSAP 是业界公认最强大、最流畅的 JavaScript 动画库。
核心思想
通过提供简洁的 API,让你用几行代码就能实现复杂的动画效果,并内置了大量的性能优化。
使用 GSAP 实现动画
你需要通过 npm 或 CDN 引入 GSAP。
CDN 引入:
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
示例:使用 GSAP 移动方块并添加缓动效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">JS Animation - GSAP</title>
<style>
#box {
width: 50px;
height: 50px;
background-color: green;
position: absolute;
top: 100px;
left: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
const box = document.getElementById('box');
// gsap.to() 是最常用的方法,表示“动画到某个状态”
// 参数1: 目标元素
// 参数2: 动画配置对象
gsap.to(box, {
duration: 2, // 动画持续2秒
x: window.innerWidth - 50, // 水平移动到窗口宽度减去方块宽度
ease: "power2.inOut", // 缓动函数,让动画更自然
repeat: 2, // 重复2次 (总共3次)
yoyo: true, // 来回运动
onComplete: () => {
console.log("动画完成!");
}
});
</script>
</body>
</html>
GSAP 的优势:
- 极其强大:支持时间轴、复杂序列、物理效果、SVG 动画等。
- 性能卓越:底层经过高度优化,性能甚至超过
requestAnimationFrame。 - 丰富的缓动效果:内置大量缓动函数,让动画生动自然。
- 跨浏览器兼容性好:处理了各种浏览器的兼容性问题。
第四部分:CSS 与 JS 动画的抉择
什么时候用 CSS,什么时候用 JS?
| 特性 | CSS 动画 | JavaScript 动画 |
|---|---|---|
| 性能 | 极高,由浏览器直接渲染,利用 GPU 加速。 | 高。requestAnimationFrame 性能很好,但通常不如 CSS。 |
| 代码量 | 少,声明式语法,简洁。 | 多,命令式语法,需要编写逻辑。 |
| 控制力 | 弱,难以与 JS 逻辑动态交互(如根据数据变化动画)。 | 极强,可以精确控制每一帧,与任何 JS 逻辑无缝集成。 |
| 复杂度 | 简单,适合固定的、预定义的动画。 | 复杂,适合动态的、复杂的、交互式的动画。 |
| 兼容性 | 较新属性(如 @property)可能需要前缀。 |
requestAnimationFrame 现代浏览器支持良好。 |
决策指南:
- 优先使用 CSS 动画:当你的动画是固定的、简单的、不需要与 JS 交互时(悬停效果、页面加载时的淡入、无限循环的旋转等)。
- 使用 JavaScript 动画:
- 当动画需要根据用户交互或数据变化而改变时(拖拽、滚动视差、根据数据变化的图表动画)。
- 当你需要对动画进行精细的、逐帧的控制时。
- 当动画非常复杂,涉及多个元素协同工作时(使用 GSAP 等库)。
第五部分:高级技巧与最佳实践
-
性能优化 -
will-change对于一些复杂的 CSS 动画,你可以提前告诉浏览器这个元素将会发生变化,浏览器会提前做好准备,提升性能。.animated-element { will-change: transform, opacity; }注意:不要滥用
will-change,它可能会占用大量内存,只在确实需要优化的元素上使用,并在动画结束后移除。 -
硬件加速 为了让浏览器利用 GPU 进行渲染,从而提升动画性能,可以对元素进行 3D 变换(即使你只是做 2D 动画)。
.animated-element { transform: translateZ(0); /* 或者 translate3d(0, 0, 0) */ }这会强制浏览器为该元素创建一个新的图层,动画将在该图层上进行,减轻主线程的压力。
-
使用
transform和opacity在动画中,优先使用transform(如translate,scale,rotate) 和opacity属性,因为这些属性不会触发浏览器的重排,只会触发重绘,性能开销远小于改变width,height,top,left等会引发重排的属性。 -
使用 Web Animations API 这是浏览器原生提供的、介于 CSS 和 JS 动画之间的 API,它提供了 JS 控制 CSS 动画的强大能力,性能接近 CSS。
const box = document.getElementById('box'); box.animate([ { transform: 'translateX(0)' }, { transform: 'translateX(300px)' } ], { duration: 1000, iterations: Infinity, direction: 'alternate' });这是一个非常有前景的 API,但目前浏览器支持度不如 GSAP 或
requestAnimationFrame广泛。
总结与学习路径
- 理解原理:从
setInterval开始,理解动画是通过“快速连续变化”实现的。 - 掌握核心:深入学习
requestAnimationFrame,这是所有 JS 动画的基石,学会如何启动、循环和停止动画。 - 实践项目:尝试用
requestAnimationFrame实现一些小动画,如小球弹跳、进度条加载等。 - 拥抱工具:当项目变得复杂时,不要犹豫,直接使用 GSAP,它能让你事半功倍,并创造出惊艳的动画效果。
- 权衡选择:学会根据需求在 CSS 和 JS 动画之间做出明智的选择,并了解性能优化的技巧。
希望这份教程能帮助你顺利掌握 JavaScript 动画!祝你编码愉快!
