css reflow和repaint

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了css reflow和repaint相关的知识,希望对你有一定的参考价值。

浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构(geometries)的进程叫做 reflow。由于 reflow 是一种浏览器中的用户拦截(user-blocking)操作,所以了解如何减少 reflow 次数,及不同的文档属性(DOM 层级(DOM depth),CSS 效率,不用类型的 style 变化)对 reflow 次数的影响对开发者来说非常必要。有时 reflow 页面中的一个元素会 reflow 它的父元素(译注:这里是复数)以及所有子元素。

Yahoo!性能工程师Nicole Sullivan写了一篇非常值得一读的分析Reflow和Repaint的文章,原文地址:http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-your-javascript-slow/以下是克军的译本:

repaint(重绘)是在一个元素的外观被改变,但没有改变布局的情况下发生,如改变visibility、outline、前景色。 "According to Opera, repaint is expensive because the browser must verify the visibility of all other nodes in the DOM tree."

当repaint发生时,浏览器会验证DOM树上的所有其它结点的visibility属性。 

reflow(回流)是导致DOM脚本执行低效的关键因素之一。页面上任何一个结点触发reflow,都会导致它的子结点及祖先结点重新渲染。Nicole举了个例子:
 
 技术分享
 
当p结点上发生reflow,div.error和body也会重新渲染,甚至h5和ol也会受到影响。

 Nicole总结了在哪些情况下会导致reflow发生:
  • 改变窗囗大小
  • 改变文字大小
  • 添加/删除样式表
  • 内容的改变,如用户在输入框中敲字(这样也会-_-||)
  • 激活伪类,如:hover (IE里是一个兄弟结点的伪类被激活)
  • 操作class属性
  • 脚本操作DOM
  • 计算offsetWidth和offsetHeight
  • 设置style属性 
reflow是不可避免的,只能将reflow对性能的影响减到最小。Nicole提出6点建议:

1.   Change classes on the element you wish to style (as low in the dom tree as possible)
尽可能限制reflow的影响范围。以上面的代码为例,要改变p的样式,class不要加在div上,通过父级元素影响子元素不好。最好直接加在p上。

2   Avoid setting multiple inline styles 
通过设置style属性改变结点样式的话,每设置一次都会导致一次reflow。所以最好通过设置class的方式。

3  Apply animations to elements that are position fixed or absolute 
实现元素的动画,它的position属性应当设为fixed或absolute,这样不会影响其它元素的布局。

4  Trade smoothness for speed 
权衡速度的平滑。比如实现一个动画,以1个像素为单位移动这样最平滑,但reflow就会过于频繁,CPU很快就会被完全占用。如果以3个像素为单位移动就会好很多。

5   Avoid tables for layout 
不要用tables布局的另一个原因就是tables中某个元素一旦触发reflow就会导致table里所有的其它元素reflow。在适合用table的场合,可以设置table-layout为auto或fixed,这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。

6   Avoid javascript expressions in the CSS (IE only)
很多情况下都会触发reflow,如果css里有expression,每次都会重新计算一遍。

 

有多种用户操作和 Dhtml 变化可能会触发 reflow。调整浏览器窗口的大小,用 javascript 计算样式(computed styles),在 DOM 中创建删除元素,改变元素的 class 都会触发 reflow。值得注意的是,有些操作会多次触发 reflow,超出你的想象。下图源自 Steve Souders 的演讲 "Even Faster Web Sites":

技术分享

从上表可以很明显的看出,在所有浏览器中并非所有 javascript 控制的样式都触发 reflow,即使触发了触发的次数也不尽相同。同时可以看出现代浏览器在控制 reflow 次数方面做的越来越好。

在 Google,我们通过多种方式对我们的页面及 Web 应用测速,同时 reflow 是我们增加 UI 时考虑的一个关键因素。我们致力于传达轻快的(lively),交互性强的(interactive)和令人愉悦的(delightful)的用户体验。

原则

下面是一些减小 reflow 的原则:

    1. 减少不必要的 DOM 层级(DOM depth)。改变 DOM 树中的一级会导致所有层级的改变,上至根部,下至被改变节点的子节点。这导致大量时间耗费在执行 reflow 上面。
    2. 尽量减少 CSS 规则,去除未用到的 CSS。
    3. 如果做复杂的表现变化,如动画,让它脱离文档流。用绝对定位或 fixed 定位来完成。
    4. 避免不必要的复杂的 CSS 选择器,尤其是后代选择器(descendant selectors),因为为了匹配选择器将耗费更多的 CPU。

以上是关于css reflow和repaint的主要内容,如果未能解决你的问题,请参考以下文章

性能优化之reflow和repaint

Repaint Reflow 的基本认识和优化

重绘(redraw或repaint),重排(reflow)

reflow和repaint

回流 (Reflow)和重绘 (Repaint)

根据浏览器渲染引擎工作原理(reflow/repaint),来优化DOM的操作