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 | 優 |
只有
transform和opacity能跳過 Layout 和 Paint,直接在 GPU 的 Composite 層完成合成。
GPU 加速:composite 層的運作原理
提升為合成層的條件
以下情況瀏覽器會將元素提升為獨立的合成層(Compositing Layer):
transform: translateZ(0)或will-change: transform<video>、<canvas>、WebGL 內容- CSS
animation/transition作用於transform或opacity 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 面板
- 開啟 DevTools → More tools → Layers
- 檢視合成層數量和顯示記憶體佔用
- 識別不必要的層提升
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);
最佳化檢查清單
- 動畫僅使用
transform和opacity - 避免在動畫中修改
width/height/top/left -
will-change僅在動畫前設定、動畫後移除 - 合成層數量 < 30
- 使用
contain: layout style paint隔離重繪範圍 - 複雜動畫使用 Web Animations API 取得精細控制
- 捲動驅動動畫使用
requestAnimationFrame節流
總結
高效能動畫的核心是讓 GPU 做 GPU 擅長的事:只動畫 transform 和 opacity,透過 will-change 預告瀏覽器,控制合成層數量避免顯示記憶體浪費。Web Animations API 提供了與 CSS 動畫相同的效能底座,同時帶來了 JS 層級的精細控制能力。
使用 CSS動畫工具 快速預覽動畫效果,使用 漸層產生器 建立高效能背景動畫,使用 圖片變換 處理圖片的 transform 操作。
本站提供瀏覽器本地工具,免註冊即可試用 →
#Web Animations API#动画性能#requestAnimationFrame#GPU加速#composite