如何实现高性能 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)
}

最佳实践

  1. 优先 CSS 动画:比 JS 动画性能好(在合成线程执行)
  2. 只动 transform/opacity:避免重排
  3. 用 will-change:对即将动画的元素提前优化
  4. 避免过多动画元素:每个合成层都消耗内存
  5. 减少同时动画的元素数量:尤其在低端设备上

同分类其他题目