页面的回流与重绘

·  阅读 565

页面呈现的具体过程

Step1

浏览器把获取到的HTML代码解析成1个DOM树,HTML中的每个tag都是DOM树中的1个节点,根节点就是我们常用的document对象。 DOM树里包含了所有HTML标签,包括使用了display:none隐藏的元素,还有用JS动态添加的元素等。

Step2

浏览器把所有样式(用户定义的CSS和用户代理)解析成样式结构体(CSSOM树),在解析的过程中会去掉浏览器不能识别的样式,比如IE会去掉-moz开头的样式,而FF会去掉_开头的样式。

Step3

DOM树和样式结构体(CSSOM树)组合后构建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),理解页面元素为一个具有填充、边距、边框和位置的盒子。

Step4

一旦render tree构建完毕后,浏览器就可以根据render tree来绘制页面了。

回流与重绘

回流

回流(reflow)指的是当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,即渲染树需要重新计算。 也就是说,回流是指DOM的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证DOM树上的所有其他节点的visibility属性,因此,回流是低效的。 每个页面至少需要一次回流,就是在页面第一次加载的时候。 在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。

回流的产生

当页面布局和几何属性改变时就会产生回流。下述情况会发生浏览器回流: DOM树的结构变化:例如节点的增减、移动等。浏览器引擎布局的过程,类似于树的前序遍历,是一个从上到下从左到右的过程。通常在这个过程中,当前元素不会再影响其前面已经遍历过的元素。所以,如果在body最前面插入一个元素,会导致整个文档的重新渲染,而在其后插入一个元素,则不会影响到前面的元素。 元素尺寸改变(边距、填充、边框、宽度和高度):当DOM元素的几何属性变化时,渲染树中的相关节点就会失效,浏览器会根据DOM元素的变化重新构建渲染树中失效的节点。 获取某些属性:当获取一些属性时,浏览器为取得正确的值也会触发重排。这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。所以,在多次使用这些值时应进行缓存。 内容改变,比如文本改变或者图片大小改变而引起的计算值宽度和高度改变; 页面渲染初始化; 浏览器窗口尺寸改变,如resize事件发生时。

重绘

重绘指的是当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color,visibility,outline等。 重绘不会带来重新布局,并不一定伴随回流(重排)。

两者的关系

回流必将引起重绘,而重绘不一定会引起回流。

如果回流的频率很高,CPU使用率会大大增加。一个元素的重排通常会带来一系列的反应,甚至触发整个文档的重排和重绘,性能代价是高昂的。

减少回流、重绘的方法

减少回流、重绘其实就是需要减少对render tree的操作(合并多次对DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。接下来介绍解决方法。

  • 尽量不用内联样式style属性,操作元素样式的时候用添加去掉class类的方式,实现合并多次改变样式属性的操作:
  • 给元素加动画的时候,可以把该元素的定位设置成absolute或者fixed(动画元素脱离文档流),这样不会影响其他元素,减少回流的Render Tree的规模。
  • 在需要经常获取那些引起浏览器重排的属性值时,要缓存到变量。
  • 尽可能在DOM树的最末端改变class。
  • 避免设置多层内联样式。
  • 动画效果应用到position属性为absolute或fixed的元素上。
  • 牺牲平滑度换取速度。
  • 免使用table布局。
  • 避免使用CSS的JavaScript表达式。
  • 避免逐项更改样式。最好一次性更改style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document。
  • 可以在一个display:none的元素上进行操作,最终把它显示出来。因为display:none上的DOM操作不会引发回流和重绘。
  • 避免循环读取offsetLeft等属性,在循环之前把它们存起来。
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改