众所周知CSS3动画性能手段的铁律之一就是,尽量不要使用会导致重排重绘的属性,之前看到这个后,就囫囵吞枣记住了,之后都会使用这个手段来优化性能,然而每次被人问起为什么要使用transform变换代替top/left等时,我都会说因为transform不会导致重绘…, 事实上原理并不是太清楚。

经过文档查阅,浏览器渲染CSS的步骤其实为:

Recalculate Style -> Layout -> Paint Setup and Paint -> Composite Layers
即:查找并计算样式 -> 排布 -> 绘制 -> 组合层

注意:

  • 查询属性会导致重排。
  • 最后这个组合层,其实类似于PS中的图层概念, 浏览器中的元素通常也是有多个层的,经过一系列计算后,还要经过GPU组合图层才渲染出页面的。
  • 重排必然导致重绘,重绘不一定触发重排。

为什么使用transform可以优化性能:

transform属性改变,发生在Composite Layers这一层,所以不会经过前面的重排,重绘;并且还会触发GPU加速。从而大大提升性能。

transform属性类似的还有opacity,也是直接在Composite Layers这一层处理透明度。

其他优化手段

  • 直接在元素上可以使用box-shaodw属性做动画:

    See the Pen Button hover effects with box-shadow by Giana (@giana) on CodePen.



    需要注意的是,直接在DOM元素上改变box-shaodw性能不如在元素的伪类上改变box-shaodw属性。参见这里(配合chrome开发者工具的timeline可以明显查看性能差异)

  • 浏览器有图层概念,一个’图层’上可以有N个DOM元素,而且如果图层中某个元素需要重绘,那么整个图层都需要重绘。 比如gif图渲染每一帧,都会导致所在图层重绘,那就应该将gif元素独立出来达到优化目的。

    附:Chrome中满足以下任意情况就会创建图层:

    1. 3D或透视变换(perspective transform)CSS属性
    2. 使用加速视频解码的<video>节点
    3. 拥有3D(WebGL)上下文或加速的2D上下文的<canvas>节点
    4. 混合插件(如Flash)
    5. 对自己的opacity做CSS动画或使用一个动画webkit变换的元素
    6. 拥有加速CSS过滤器的元素
    7. 元素有一个包含复合层的后代节点(一个元素拥有一个子元素,该子元素在自己的层里)
    8. 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)