加速你的CSS

关于CSS优化这一块儿,人们常常的感觉是这个页面很平滑或者是很流畅,所已对CSS的优化可以涉及到两个方面。
一个是减少页面reflow、repaint的次数,还有一种就是通过启动硬件加速,来调用硬件性能实现CSS的优化。

关于平滑

当人们感觉到“平滑”时,一般是每一秒在屏幕上绘画的帧数超过了某一个值(FPS),
有一个非官方的值,即超过了30或者是更多。
本地应用要比Web apps感觉良好,很大的原因在于执行swiping, tapping, pinching等保持一个较高的FPS值。
但是现在很多的浏览器厂商都对一些特定的CSS属性提供了图形硬件加速。

repaint, reflow/relayout, restyle

不同的浏览器有不同的渲染过程,但是大部分浏览器都拥有下面的过程:

  • parse HTML source code -> DOM tree
  • parse CSS代码,在这个部分就会剔出掉一些无用的前缀样式,比如-moz, -webkit等
  • 下面就到了最有兴趣的一部分了,rendering tree。render tree更像是缩短版的DOM tree,但是也有一些不一样的地方,
    render tree 是知道样式信息的,所以你对一个div设置display: none,它是不会出现在render tree 中的。同样的
    还有其它的不可见的元素,比如head和head里面的元素。

reflow & repaint

当页面完成默认的绘制过后,当改变创建render tree的某些输入信息是会导致reflow或者是repaint
1.render tree的一部分需要重新验证或者是node的位置信息需要被重新计算,会导致发生reflow.
2.当屏幕的一部分需要被更新的时候,不管是一个节点的几何属性发生更改或者是样式更改。这种屏幕更新的
操作叫做repaint.

1
2
3
4
var bStyle = document.body.style;
bStyle.padding = "20px"; // reflow, repaint;
bStyle.border = "10px solid red" //another reflow 和repaint
bStyle.color = "blue" // repaint only

reflow和repaint在浏览器端的优化

浏览器为了减小repaint和reflow带来的负面效应,一般会延迟执行,或者是攒在一起集中执行。简单的说,浏览器会维护一个
列表,这个列表里面存放了需要执行的操作,它可以将多个操作进行合并执行,从而减少reflow或者repaint的次数。但是有些脚步
会阻止浏览器做这样的优化,让浏览器立即更新列表。这个常常发生在获取样式信息的时候,例如:

  1. offsetTop, offsetLeft, offsetWidth, offsetHeight
  2. scrollTop/Left/Width/Height
  3. clientTop/Left/Width/Height
  4. getComputedStyle(), or currentStyle in IE

reflow和repaint在程序上的优化

  • 不要单一的去改变样式,而是通过使用改变类名或者是修改cssText属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      //bad
      var left = 10, top = 20;
      ele.style.top = top + "px";
      ele.style.left = left + "px";
    
      //good
      el.className += "current";
    
      //good
      el.style.cssText = ";left: " + left + "px; top: " + top + "px";
    
  • 将对DOM的改变离线话,即不在动态的DOM树中,而是:

    • 使用documentFragements来保留临时的更改
    • 克隆你要改变的节点,然后在克隆的节点上对DOM进行改变,然后在改变原来的节点
    • 使用display: none先把元素进行隐藏,然后在对该元素进行改变。改变完后在进行显示
  • 不要循环地对computed样式进行获取,而是通过对样式信息进行缓存。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
        // no-no!
        for(big; loop; here) {
            el.style.left = el.offsetLeft + 10 + "px";
            el.style.top  = el.offsetTop  + 10 + "px";
        }
    
        // better
        var left = el.offsetLeft,
            top  = el.offsetTop
            esty = el.style;
        for(big; loop; here) {
            left += 10;
            top  += 10;
            esty.left = left + "px";
            esty.top  = top + "px";
        }
    
  • 在写程序的时候多考虑哪些操作可能会造成大面积的reflow或者是repaint, 然后尽量去避免这些操作。

可以启动GPU加速的属性

  • 常规的布局(layout)组合
  • CSS3transitions
  • CSS3 3D transforms
  • Canvas 绘画
  • WebGL 3D 绘画