[Web 性能] repaint and reflow (重绘和回流)

来源:互联网 发布:淘宝编辑宝贝流程 编辑:程序博客网 时间:2024/06/23 00:10

页面呈现流程

在介绍重绘和回流之前, 先看一下HTML 页面呈现的流程。

可能各浏览器会有一些细微的差别, 但基本上大同小异。

1.  浏览器把获取到的html代码解析成1个Dom树。根节点就是document 对象,这里包含了所有的html tag,包括display:none隐藏,还有用JS动态添加的元素等。

2. 浏览器把所有样式(主要包括css和浏览器的样式设置)解析成样式结构体,在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而firefox会去掉_开头的样式。

3. dom tree和样式结构体结合后构建呈现树(render tree),render tree有点类似于dom tree,但其实区别有很大,render tree能识别样式,render tree中每个node都有自己的style,而且render tree不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现的,所以就不会包含到render tree中。注意 visibility:hidden隐藏的元素还是会包含到render tree中的,因为visibility:hidden 会影响布局(layout),会占有空间。根据css2的标准,render tree中的每个节点都称为box(Box dimensions),box所有属性:width,height,margin,padding,left,top,border等

4. 浏览器就可以根据render tree来绘制页面了


什么是reflow 和 repaint?

什么是reflow?

reflow指的是计算页面布局。某个节点reflow时会重新计算节点的尺寸和位置,而且还有可能触发其子节点、祖先节点和页面上的其他节点reflow。在这之后再触发一次repaint。

当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流,每个页面至少需要一次回流,就是在页面第一次加载的时候。


什么是repaint?

repiant或者redraw遍历所有的节点检测各节点的可见性、颜色、轮廓等可见的样式属性,然后根据检测的结果更新页面的响应部分。

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘


从上面可以看出,回流必将引起重绘,而重绘不一定会引起回流。


有时 reflow 页面中的一个元素会 reflow 它的父元素(译注:这里是复数)以及所有子元素。

reflow对性能的影响非常大,但是很不幸,reflow很容易被触发。


什么会导致回流

很多状况下都会导致回流:

1. 调整窗口大小(Resizing the window)

2. 改变字体(Changing the font)

3. 增加或者移除样式表(Adding or removing a stylesheet)

4. 内容变化,比如用户在input框中输入文字(Content changes, such as a user typing text in
an input box)

5. 激活 CSS 伪类,比如 :hover (IE 中为兄弟结点伪类的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))

6. 操作 class 属性(Manipulating the class attribute)

7. 脚本操作 DOM(A script manipulating the DOM)

8.计算 offsetWidth 和 offsetHeight 属性(Calculating offsetWidth and offsetHeight)

9. 设置 style 属性的值 (Setting a property of the style attribute)


CSS 避免回流,提升性能

1. 尽可能在DOM树的最末端改变class

回流可以自上而下,或自下而上的回流的信息传递给周围的节点。回流是不可避免的,但可以减少其影响。尽可能在DOM树的里面改变class,可以限制了回流的范围,使其影响尽可能少的节点。例如,你应该避免通过改变对包装元素类去影响子节点的显示。面向对象的CSS始终尝试获得它们影响的类对象(DOM节点或节点),但在这种情况下,它已尽可能的减少了回流的影响,增加性能优势。

2. 避免设置多层内联样式

我们都知道与DOM交互很慢。我们尝试在一种无形的DOM树片段组进行更改,然后整个改变应用到DOM上时仅导致了一个回流。同样,通过style属性设置样式导致回流。避免设置多级内联样式,因为每个都会造成回流,样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一个reflow。

3. 动画效果应用到position属性为absolute或fixed的元素上

动画效果应用到position属性为absolute或fixed的元素上,它们不影响其他元素的布局,所它他们只会导致重新绘制,而不是一个完整回流。这样消耗会更低。

4. 牺牲平滑度换取速度

Opera还建议我们牺牲平滑度换取速度,其意思是指您可能想每次1像素移动一个动画,但是如果此动画及随后的回流使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动。

5. 避免使用table布局

避免使用table布局。可能您需要其它些避免使用table的理由,在布局完全建立之前,table经常需要多个关口,因为table是个和罕见的可以影响在它们之前已经进入的DOM元素的显示的元素。想象一下,因为表格最后一个单元格的内容过宽而导致纵列大小完全改变。这就是为什么所有的浏览器都逐步地不支持table表格的渲染(感谢Bill Scott提供)。然而有另外一个原因为什么表格布局时很糟糕的主意,根据Mozilla,即使一些小的变化将导致表格(table)中的所有其他节点回流。

6. 避免使用CSS的JavaScript表达式

这项规则较过时,但确实是个好的主意。主要的原因,这些表现是如此昂贵,是因为他们每次重新计算文档,或部分文档、回流。正如我们从所有的很多事情看到的:引发回流,它可以每秒产生成千上万次。当心!


什么情况下触发浏览器的repaint/reflow?

1. 页面首次加载时

2. DOM元素的添加、修改(内容)、删除( Reflow + Repaint)

3. 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)

4. 应用新的样式或者修改任何影响元素外观的属性

5. Resize浏览器窗口、滚动页面

6.读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE))



如何减小reflow ?


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

工具


当Mozilla公开MozAfterPaint Firefox API时,互联网界议论纷纷。

  • 更新:Google的Lindsey Simon写了个可以在任意浏览器下测试回流时间的书签工具。非常的赞,注意:所有的震动都是正常的。//zxx: 我测试此链接为500错误
  • John Resig写了个书签工具来可视化绘制事件。
  • Kyle Scholz创建了一个工具用来在页面加载之前可视化绘制事件
  • Yoono的Alex创建了XUL分析工具

是否其他人见到过好的关于回流评估的工具?请发送告知我。

还有其他一对不是直接用来处理回流的工具。

  • IE浏览器视觉往返分析仪(VRTA),因为微软起了个这么有趣的名字,所以我们可能还真的会用它。:)
  • 专为WPF的性能分析工具


0 0
原创粉丝点击