如何实现高性能 CSS 动画?哪些属性会触发重排?
重排(Reflow)vs 重绘(Repaint)vs 合成
| 操作 | 性能 | 属性示例 |
|---|---|---|
| 重排 | 最差 | width、height、margin、top、left |
| 重绘 | 中等 | color、background、box-shadow |
| 合成 | 最好 | transform、opacity |
高性能动画原则
只动画 transform 和 opacity,它们只触发合成层,不引起重排/重绘。
/* ❌ 差:触发重排 */
.move {
transition: left 0.3s, top 0.3s;
}
.move:hover {
left: 100px;
top: 100px;
}
/* ✅ 好:只触发合成 */
.move {
transition: transform 0.3s;
}
.move:hover {
transform: translate(100px, 100px);
}常见属性性能分级
| 级别 | 属性 |
|---|---|
| ✅ 合成层 | transform、opacity、filter |
| ⚠️ 重绘 | color、background、border-color、box-shadow |
| ❌ 重排 | width、height、margin、padding、top、left、font-size |
will-change 提示浏览器
.animated {
will-change: transform, opacity;
/* 提前告知浏览器这些属性会变化,提前优化 */
}
/* 动画结束后移除 */
.animated.done {
will-change: auto;
}requestAnimationFrame
JS 动画使用 requestAnimationFrame 而非 setInterval:
function animate(element, target) {
let current = 0
function step() {
current += (target - current) * 0.1
if (Math.abs(target - current) < 0.1) {
element.style.transform = `translateX(${target}px)`
return
}
element.style.transform = `translateX(${current}px)`
requestAnimationFrame(step)
}
requestAnimationFrame(step)
}最佳实践
- 优先 CSS 动画:比 JS 动画性能好(在合成线程执行)
- 只动 transform/opacity:避免重排
- 用 will-change:对即将动画的元素提前优化
- 避免过多动画元素:每个合成层都消耗内存
- 减少同时动画的元素数量:尤其在低端设备上