关于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的次数。但是有些脚步
会阻止浏览器做这样的优化,让浏览器立即更新列表。这个常常发生在获取样式信息的时候,例如:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- 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 绘画