JavaScript动画核心在于平滑、低阻塞、高适配:优先用requestAnimationFrame对齐屏幕刷新,避免setTimeout;用transform/opacity配合CSS transition交由合成器线程处理;慎用触发布局的属性;滚动动画注意兼容性与控制粒度;需综合判断触发时机、中断逻辑与降级策略。

JavaScript 实现动画,核心不在“怎么动”,而在“怎么不动声色地动”——真正影响体验的是过渡是否平滑、是否受主线程阻塞、是否适配不同刷新率。直接用 setTimeout 或 setInterval 手写帧循环,现在基本是退路,不是首选。
该用 requestAnimationFrame 而不是 setTimeout
浏览器知道什么时候重绘,requestAnimationFrame 会把回调对齐到下一帧(通常是 60fps),而 setTimeout(fn, 16) 只是“尽量 16ms 后执行”,实际可能堆积、跳帧、与屏幕刷新不同步。
- 必须在回调里再次调用自身,形成循环:
function animate() { /* 更新样式 */ requestAnimationFrame(animate); } - 不要在回调里做耗时操作(如大量 DOM 查询、复杂计算),否则直接拖慢帧率
- 动画暂停时记得保存
requestId并调用cancelAnimationFrame(id),避免内存泄漏
CSS transition 和 transform 是最省心的平滑方案
只要动的是 transform(translate、scale、rotate)或 opacity,浏览器会交给合成器线程处理,不触发重排(reflow)和重绘(repaint),性能几乎无损。
- 写法示例:
element.style.transition = 'transform 0.3s ease-out, opacity 0.2s linear';,然后改element.style.transform = 'translateX(100px)'; - 避免对
top、left、width、height等触发布局的属性做 transition,它们强制同步计算,卡顿明显 - 如果需要 JS 控制起止点但又想靠 CSS 过渡,推荐用 class 切换 +
getComputedStyle触发重排后再加 class
用 scrollTo 或 scrollIntoView 做滚动动画要小心兼容性
原生滚动 API 支持 { behavior: 'smooth' },但 Safari 旧版、部分安卓 WebView 不支持,且无法精细控制缓动曲线。
立即学习“Java免费学习笔记(深入)”;
-
element.scrollTo({ top: 100, behavior: 'smooth' });是最简方案,但不可中断、不可监听进度 - 若需自定义 easing(如
cubic-bezier(0.34, 1.56, 0.64, 1))或监听每一帧,仍得回退到requestAnimationFrame+window.scrollY计算 - 注意:
scrollIntoView({ behavior: 'smooth' })在某些情况下会意外触发focus,影响可访问性
真正难的不是让元素动起来,而是判断该不该动、在哪动、动多快——比如用户快速连续触发时要不要防抖,动画中途用户交互了要不要优雅中断,以及是否该降级到 will-change: transform 提前告知浏览器优化。这些细节没处理好,再“平滑”的代码也会显得卡顿。











