Web Animations API 与高性能动画:GPU 加速与 composite 优化

性能优化(更新于 2026年6月6日)

浏览器渲染管线与动画性能

浏览器渲染一帧需要经过:Style → Layout → Paint → Composite。动画性能的关键在于跳过尽可能多的阶段

属性类型 触发阶段 性能
width/height/margin Layout → Paint → Composite
color/background Paint → Composite
transform/opacity 仅 Composite

只有 transformopacity 能跳过 Layout 和 Paint,直接在 GPU 的 Composite 层完成合成。


GPU 加速:composite 层的工作原理

提升为合成层的条件

以下情况浏览器会将元素提升为独立的合成层(Compositing Layer):

  • transform: translateZ(0)will-change: transform
  • <video><canvas>、WebGL 内容
  • CSS animation/transition 作用于 transformopacity
  • position: fixed(部分浏览器)

合成层的代价

每个合成层 = 独立的 GPU 纹理 = 显存占用

层过多 → 显存压力 → 反而降低性能

建议:合成层数量控制在 30 个以内,移动端更少。


will-change:正确使用与常见误区

基本用法

.animating-element {
  will-change: transform, opacity;
}

最佳实践

/* 差:全局声明,浪费资源 */
.card {
  will-change: transform;
}

/* 好:仅在交互前声明,交互后移除 */
.card:hover {
  will-change: transform;
}
.card.is-dragging {
  will-change: transform;
}
// JS 动态控制 will-change
element.addEventListener('mouseenter', () => {
  element.style.willChange = 'transform';
});
element.addEventListener('transitionend', () => {
  element.style.willChange = 'auto';
});

原则:will-change 是"预告"而非"优化开关",仅在即将发生动画时设置,动画结束后移除。


Web Animations API:element.animate()

基本语法

const animation = element.animate(
  [
    { transform: 'translateX(0px)', opacity: 1 },
    { transform: 'translateX(300px)', opacity: 0.5 }
  ],
  {
    duration: 600,
    easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
    fill: 'forwards',
    iterations: 1
  }
);

与 CSS Animations 对比

特性 CSS Animations Web Animations API
声明方式 CSS @keyframes JS element.animate()
动态控制 难(需操作 class) 简单(play()/pause()/reverse()
动态关键帧 不支持 支持运行时生成
Promise 集成 animation.finished/animation.ready
性能 相同 相同(同一引擎)
浏览器优化 可预解析 运行时优化

动画控制 API

const anim = element.animate(keyframes, options);

anim.pause();
anim.play();
anim.reverse();
anim.finish();
anim.cancel();

anim.playbackRate = 2.0;
anim.currentTime = 300;

anim.finished.then(() => {
  console.log('动画完成');
});

requestAnimationFrame 与动画调度

为什么不用 setTimeout/setInterval

// 差:与屏幕刷新不同步,可能丢帧
setInterval(() => {
  element.style.transform = `translateX(${x}px)`;
}, 16);

// 好:与浏览器刷新率同步
function animate(timestamp) {
  const progress = (timestamp - startTime) / duration;
  element.style.transform = `translateX(${targetX * progress}px)`;
  if (progress < 1) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

rAF 与 WAAPI 的配合

// 复杂场景:WAAPI 处理简单动画,rAF 处理需要逐帧计算的动画
const scrollAnim = element.animate(
  [{ transform: 'translateY(0)' }, { transform: 'translateY(-100px)' }],
  { duration: 300, fill: 'forwards' }
);

// 滚动驱动动画仍需 rAF
let ticking = false;
window.addEventListener('scroll', () => {
  if (!ticking) {
    requestAnimationFrame(() => {
      element.style.transform = `translateY(${window.scrollY * 0.5}px)`;
      ticking = false;
    });
    ticking = true;
  }
});

Composite 层优化实战

减少重绘区域

/* 差:整个容器重绘 */
.container {
  animation: pulse 1s infinite;
}
@keyframes pulse {
  0%, 100% { background: #fff; }
  50% { background: #f0f0f0; }
}

/* 好:仅动画层重绘 */
.container {
  position: relative;
}
.container::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0);
  animation: pulse 1s infinite;
  will-change: opacity;
}
@keyframes pulse {
  0%, 100% { opacity: 0; }
  50% { opacity: 0.05; }
}

避免层爆炸

/* 差:每个列表项都创建合成层 */
.list-item {
  will-change: transform;
}

/* 好:仅动画中的元素提升 */
.list-item.is-animating {
  will-change: transform;
}

contain 属性隔离

.card {
  contain: layout style paint;
}

contain 告诉浏览器该元素的样式/布局/绘制不会影响外部,浏览器可以安全优化。


性能测量

Chrome DevTools Layers 面板

  1. 打开 DevTools → More tools → Layers
  2. 查看合成层数量和显存占用
  3. 识别不必要的层提升

Performance 面板分析

帧时间线中:
- 绿色 = 绘制(Paint)
- 紫色 = 布局(Layout)
- 透明 = 合成(Composite)← 理想状态

帧率检测

let lastTime = performance.now();
let frames = 0;

function measureFPS() {
  frames++;
  const now = performance.now();
  if (now - lastTime >= 1000) {
    console.log(`FPS: ${frames}`);
    frames = 0;
    lastTime = now;
  }
  requestAnimationFrame(measureFPS);
}
requestAnimationFrame(measureFPS);

优化检查清单

  • 动画仅使用 transformopacity
  • 避免在动画中修改 width/height/top/left
  • will-change 仅在动画前设置、动画后移除
  • 合成层数量 < 30
  • 使用 contain: layout style paint 隔离重绘范围
  • 复杂动画使用 Web Animations API 获取精细控制
  • 滚动驱动动画使用 requestAnimationFrame 节流

总结

高性能动画的核心是让 GPU 做 GPU 擅长的事:只动画 transformopacity,通过 will-change 预告浏览器,控制合成层数量避免显存浪费。Web Animations API 提供了与 CSS 动画相同的性能底座,同时带来了 JS 级别的精细控制能力。

使用 CSS动画工具 快速预览动画效果,使用 渐变生成器 创建高性能背景动画,使用 图片变换 处理图片的 transform 操作。

本站提供浏览器本地工具,免注册即可试用 →

#Web Animations API#动画性能#requestAnimationFrame#GPU加速#composite