CSS 動畫效能最佳化:讓動畫絲滑流暢的技巧
CSS 動畫效能最佳化:讓動畫絲滑流暢的技巧
流暢的動畫效果能大幅提升使用者體驗,但動畫如果沒有注意效能,可能讓整個頁面卡頓甚至難以使用,在行動裝置上尤其明顯。這篇文章分享 CSS 動畫效能最佳化的核心技巧。
瀏覽器渲染流程基礎
瀏覽器渲染分為幾個步驟:
- Style:計算 CSS 樣式
- Layout:計算元素幾何位置(尺寸、位置)
- Paint:填充像素
- Composite:合成圖層
動畫優化的核心原則:盡量只觸發 Composite,避免 Layout 和 Paint。
哪些屬性會觸發 Layout(重排)
/* 這些屬性的變更會觸發 Layout,動畫中應避免 */
.bad-animation {
width: 200px;
height: 100px;
margin: 20px;
top: 50px;
left: 100px;
}transform 和 opacity 是首選
/* 好的做法:只觸發 Composite */
.card {
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.card:hover {
transform: translateY(-4px); /* 不觸發 Layout */
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}will-change 提示瀏覽器
.animated-card {
will-change: transform; /* 提前建立 GPU 圖層 */
}
/* 動畫結束後移除,避免佔用過多記憶體 */
.animated-card.animation-done {
will-change: auto;
}注意:will-change 不要濫用,每個使用了它的元素都會佔用更多 GPU 記憶體。
實際案例:卡片懸停效果
/* 不好的版本(觸發 Layout) */
.card-bad:hover {
margin-top: -4px; /* 觸發 Layout! */
}
/* 好的版本(只觸發 Composite) */
.card-good {
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
box-shadow 0.3s ease;
will-change: transform;
}
.card-good:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}常用動畫範例
/* 旋轉載入指示器 */
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid #f0f0f0;
border-top-color: #3498db;
border-radius: 50%;
animation: spin 0.8s linear infinite;
will-change: transform;
}
/* 脈動效果 */
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.05); opacity: 0.8; }
}減少重排的 JavaScript 技巧
// 壞的做法:交替讀寫,每次都強制 Layout
element.style.width = '200px';
console.log(element.offsetWidth); // 強制 Layout
element.style.height = '100px';
// 好的做法:批量讀取再批量寫入
const width = element.offsetWidth;
const height = element.offsetHeight;
element.style.width = (width * 2) + 'px';
element.style.height = (height * 2) + 'px';
// 使用 requestAnimationFrame
function animate() {
requestAnimationFrame(() => {
element.style.transform = `translateX(${position}px)`;
position += 2;
if (position < 300) animate();
});
}CSS Custom Properties 管理動畫變數
:root {
--duration-fast: 150ms;
--duration-normal: 300ms;
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
.button {
transition: transform var(--duration-fast) var(--ease-spring);
}
.button:hover { transform: scale(1.05); }
.button:active { transform: scale(0.97); }尊重使用者偏好設定
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}效能偵測工具
Chrome DevTools Performance 面板可以分析每帧耗時,目標維持在 16.7ms(60fps)以下。啟用 Rendering 面板中的 "Paint flashing" 可以視覺化重繪區域,找出效能問題所在。
分享這篇文章