页面的重绘与回流

   上次在面试中,面试官问了我一个关于页面重绘和回流的问题,我解释的不怎么好。今天把它整理了一下,又参考了一些其他的文章。

  参考文章:http://www.css88.com/archives/4996

  页面加载过程

     1、浏览器将获取到的HTML代码解析成一个DOM树,HTML中的每一个标签都是DOM树中的一个节点,根节点就是document。DOM树中包含了所有的HTML标签,同时也包含了display:none 隐藏和JS动态添加的元素等

     2、浏览器将所有的样式(CSS)解析成样式结构体(CSS Model),在解析过程中会去掉浏览器不识别的样式。

     3、DOM Tree 和样式结构体组合后构建render tree。 render tree类似于DOM tree。但是有较大差别。render树中的每个节点都有自己的样式,但是render tree中不包含display:none的元素。但是visiblity:hidden的隐藏元素会包含在render Tree中。因为visibility:hidden会影响布局(layout),且在文档流中占据一定的空间。

       4、一旦render Tree 构建完毕,浏览器就可以根据render tree绘制页面了

  回流与重绘

  1、什么是回流?

    当render tree 中的一部分(或者全部)因为元素的规模尺寸、布局隐藏等改变需要重新构建。这就是回流。

  2、什么是重绘?

    在回流的时候,浏览器会使渲染树中受影响的部分失效,并重新绘制这部分的渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘

  3、什么情况下浏览器会发生重绘?

    重绘不一定引起回流,但是回流一定会影响重绘。只是改变某些元素的属性并且这些属性会影响到元素的外观、风格,不会影响页面的布局,比如backgorund-color;color等;visability:hidden只重绘不回流

  4、什么情况下,浏览器会发生回流?(重要)

    当页面布局或者几何大小发生变化时就会发生回流。

    ①添加或删除可见的DOM元素;

    ②元素的位置变化

    ③元素的尺寸变化--内容区域、边框、内外边距、宽高

    ④内容改变--文本内容改变或者图片大小改变而引起的计算值宽度和高度改变

    ⑤页面渲染的初始化

    ⑥浏览器可视窗口变化---resize时间发生时、或者浏览器的字体大小改变时(用户操作)

         聪明的浏览器 (见文章 http://www.css88.com/archives/4996;写的很好)

    如何优化页面?

    减少回流和重绘就是减少对render tree的操作(合并多次DOM修改和样式修改),减少对一些元素style的请求。具体方法如下:

    1、同时添加子元素和父元素时,应先在内存中将子元素拼接到父元素中,最后在整体一次性将父元素添加到文档流中---这样只会发生一次layout

    2、如果多次同时添加多个平级元素时,应该使用文档片段

    什么是文档片段:内存中临时存储的多个平级子元素的虚拟父元素

      何时使用: 只要是添加多个平级的子元素时,都要先将子元素加入到文档片段中,再一次性将文档片段添加到DOM树

            实例如下:          

使用文档片段
<ul id="container"> </ul> <script type="text/javascript"> var container = document.getElementById('container'); console.time(); var fragment = document.createDocumentFragment(); for(var i = 0;i<50000;i++){ fragment.appendChild(document.createElement('li')); } container.appendChild(fragment); console.timeEnd(); </script>
//总耗时default: 76.31201171875ms
不使用文档片段

<script type="text/javascript">
    var container = document.getElementById('container');
console.time();
for(var i = 0;i<50000;i++){
container.appendChild( document.createElement('li'))
}
console.timeEnd();
</script>
//default: 88.941162109375ms

  3、直接改变className,如果动态改变样式,可以使用cssText

  4、由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排。 

  5、使用cloneNode(true/false)和replaceChild 技术,引发一次回流和重绘

  6、不要经常访问会引起浏览器flush队列的属性,如果确实要访问的话,可以利用缓存;也就是说需要经常去那些引起浏览器重排的属性时,需要缓存到变量中,再调用。

  7、让元素脱离动画流,减少回流的Render Tree的规模

                 

  

原文地址:https://www.cnblogs.com/bllx/p/8611122.html