理解浏览器的重绘与回流(repaint&&reflow)

  今天在做练习的时候,遇到了重绘与回流这个词,表示连个毛都没有听过。遂查之,首先将网上的(http://blog.sina.com.cn/s/blog_8dace7290102wezv.html)关于这两个词的领悟粘贴如下:

一.  浏览器渲染过程  

渲染:就是把浏览器把HTML代码以css定义的规则显示在浏览器窗口的过程

浏览器解析HTML的基本过程:
 
1  用户输入网址,浏览器向服务器发出请求,服务器返回html文件
 
2  浏览器载入html代码,发现标签内有一个标签引用外部css文件
 
3 浏览器又发出css文件的请求,服务器返回这个css文件
 
4 浏览器继续载入html中的部分的代码,并且css文件已经拿到手了,可以渲染页面
 
5 浏览器在代码中发现一个理解浏览器的重绘与回流(repaint&&reflow)标签引用关了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码
 
6 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来渲染这部分代码
 
7  浏览器发现了一个包含一行javascript代码的script标签,赶快运行它
 
8 javascript脚本执行了这条语句,命令浏览器隐藏代码中某个,杯具了,突然就少了一个元素,浏览器不得不重新渲染这部分代码
 
9  终于等到的到来,浏览器泪流满面 
 
10   等等,还没完,用户点了一个界面中的“换肤”按钮,javascript让浏览器换了一个标签中的css的路径
 
 
11 浏览器召集了在座的各位:"大伙需要收拾下行李,咱得重新来过",浏览器向服务器请求了新的css文件,重新渲染页面当页面的布局发生变化时,浏览器会回过头来重新渲染,这就是页面变慢的原因。
 
二.  渲染树(render tree)

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

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

3.DOM树和样式结构体组合后构建render tree(渲染树),render tree类似于DOM树,但区别很大,render tree 能识别样式,render tree的每一个节点都有自己的样式,而且render tree中不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于呈现,而且不会影响呈现。

注意:visibility:hidden隐藏的元素还是会包含到render tree中,因为visibility:hidden会影响布局(layout),会占有空间。根据css2的标准,render tree中的每个节点都称为Box(Box demensions),理解页面元素为一个具有填充,边距,边框和位置的盒子。

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

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

三.  重绘与回流的定义

  重绘:当前元素的样式(背景颜色、字体颜色等)发生改变的时候,我们只需要把改变的元素重新的渲染一下即可,重绘对浏览器的性能影响较小,所以 一般不考虑。

  发生重绘的情形:改变容器的外观风格等,比如background:black等。改变外观,不改变布局,不影响其他的dom。

  回流:是指浏览器为了重新渲染部分或者全部的文档而重新计算文档中元素的位置和几何构造的过程。

  因为回流可能导致整个dom树的重新构造,所以是性能的一大杀手

  一个元素的回流导致了其所有子元素以及DOM中紧随其后的祖先元素的随后的回流.

四.  触发回流的操作

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)

10.fixed定位的元素,在拖动滚动条的时候会一直回流

五.  如何避免回流

  1.  一起变化

  如果要改变一个元素的样式,可以将所有样式集中在一个class上面一次变化,而不是变化几次,比如:

<style type="text/css">
.changeStyle { width: 100px; height: 100px; }
</style>
<script type="text/javascript">
$(document).ready(function () {
var el = $('id');
//1
el.css('width', '100px');
el.css('height', '100px');
//2
el.css({ 'width': '100px;', 'height': '100px;' });
//3
el.addClass('changeStyle');
});
</script>

  应该使用第三种,这样只重绘一次。

  2.  具有动画效果请使用absolute

  3.  避免使用表格布局

  4.  不要使用CSS表达式

  5.  在最末改变元素

  因为回流是自上而下的,所以下不及上,我们在最后面修改信息对全局影响越少。

  6.  动画移动时候,要控制

  比如我们拖动元素时候,我是在他x或者y坐标改变5px才操作,这样虽说降低了平滑度,但是对性能有提高

  7.  如果你想让复杂的表现发生改变,例如动画效果,那么请在这个流动线之外实现它。使用position-absolute或position-fixed来实现它。

  8.  既然计算offsetWidth也会引起回流,那么就拿一个变量保存它

  9.  当我们需要向文档中添加节点时,可以用文档碎片的方式去解决这个问题的,当我们需要给DOM中添加新的元素的时候,先将其放在一个容器中,然后统一添加,这样就只产生了一次回流。如下:

var frg = document.createDocumentFragment();//创建了一个文档碎片:相当于一个容器,把动态创建的li先放到容器中,最后一起添加到页面中(只引发一次回流)
for (var i = 0; i < ; i++) {
var oLi = document.createElement("li");
oLi.onmouseover = function () {
this.style.backgroundColor = "#22b909";
}
oLi.onmouseout = function () {
this.style.backgroundColor = "";
}
frg.appendChild(oLi);
}
oUl.appendChild(frg);

资料来源:

  http://aijuans.iteye.com/blog/1910614

  http://m.blog.csdn.net/article/details?id=50696328

  http://www.360doc.cn/article/10504424_435836011.html

  http://www.zhangxinxu.com/wordpress/2010/01/%E5%9B%9E%E6%B5%81%E4%B8%8E%E9%87%8D%E7%BB%98%EF%BC%9Acss%E6%80%A7%E8%83%BD%E8%AE%A9javascript%E5%8F%98%E6%85%A2%EF%BC%9F/

    

回流是指浏览器为了重新渲染部分或者全部的文档而重新计算文档中元素的位置和几何构造的过程
上一篇:Elasticsearch的几种架构(ELK,EL,EF)性能对比测试报告


下一篇:【HTML】canvas学习小结