关于reflow和repaint

来源:互联网 发布:matlab2016a mac 破解 编辑:程序博客网 时间:2024/06/06 08:49

接触前端不久的小白,觉得大神们的总结不错,老实转过来学习学习。 O(∩_∩)O


一、什么是repaint/reflow?

页面在加载的过程中,需要对文档结构进行解析,同时需要结合各种各样的样式来计算这个页面长什么样子,最后再经过浏览器的渲染页面就出现了。这整个过程细说起来还是比较复杂,其中充满了repaint和reflow。对于DOM结构中的各个元素都有自己的盒子(模型),这些都需要浏览器根据各种样式(浏览器的、开发人员定义的等)来计算并根据计算结果将元素放到它该出现的位置,这个过程称之为reflow;当各种盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来后,浏览器于是便把这些元素都按照各自的特性绘制了一遍,于是页面的内容出现了,这个过程称之为repaint。

以上提到的只是在页面加载时必然会出现的repaint和reflow,除此之外,在页面加载完成后,用户的一些操作、脚本的一些操作都会导致浏览器发生这种行为,具体在后文阐述。

另外,关于浏览器渲染的更为详细的资料可以参考以下,涵盖了IE以及Firefox:

Understanding Internet Explorer Rendering Behaviour

Notes on HTML Reflow

 

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

除了页面在首次加载时必然要经历该过程之外,还有以下行为会触发这个行为:

  • DOM元素的添加、修改(内容)、删除( Reflow + Repaint)
  • 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)
  • 应用新的样式或者修改任何影响元素外观的属性
  • Resize浏览器窗口、滚动页面
  • 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE))

在继续下面的文章之前,先介绍一款强大的性能分析工具-dynaTrace,借助该功能能够清晰的得到页面中的资源消耗情况,从而对症下药。另外,更细节的方面是它可以跟踪每个函数调用所造成的CPU消耗、Repaint/Reflow。接下来就借助该工具来测试一下以上描述的几点情况。

 

DOM元素的增删改

先看代码

HTML:

这里是第1个节点
这里是第2个节点
这里是第3个节点

Javascript:

        function $(id){            return document.getElementById(id);        }        function addNode(){            var n = document.createElement('div');            n.innerHTML = 'New Node';            $('test1').appendChild(n);        }        function modNode(){            $('test2').innerHTML = 'hello';        }        function delNode(){            $('test3').parentNode.removeChild($('test3'));        }

在依次点击完每一个按钮后,我们来看看dynaTrace的情况,首先是一目了然的点击事件分布

 

放大之后来看一下每个事件的repaint/reflow情况:

 

增加节点:

 

修改节点:

删除节点:

图中的绿色部分表示的是reflow和repaint过程,其中比较短的绿条标示的reflow过程,后面长条部分表示的是repaint过程。从图中可以看出,对DOM节点的增删改都会造成reflow和repaint,由于改动小所以reflow消耗的时间很短,但是由于repaint是全局的,因此消耗的时间都比较长。

 

修改DOM元素前景色

var n = $('colorNode');n.style.color = 'red';

 

 

从上图中可以看到修改字体颜色后,浏览器只有repaint而没有reflow。接下来试试修改背景色:

var n = $('colorNode');n.style.backgroundColor = 'red';

由图中可以看出,修改背景色也会造成reflow和repaint。另外,经过测试发现,只要是修改元素的cssText属性,不论它的值是什么,都会导致浏览器reflow和repaint,因此在某些时候选择特定的样式属性赋值会有更好的效果。

Resize浏览器窗口以及拖动滚动条

 

 

测试中的操作如下:缩小浏览器窗口->放大浏览器窗口->拖动页面滚动条至页面底部。从图中可以看到Resize浏览器窗口以及拖动滚动条都会造成浏览器的repaint,而且CPU的消耗也比较大,尤其是拖动滚动条的时候。

读取Layout属性

根据各种参考资料中的描述,在用Javascript读取DOM节点的Layout属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE)) 的时候也会触发repaint,不过在以下的测试例子中并没有发现这一点。

var n = $('colorNode');var temp = document.documentElement.currentStyle;temp = n.offsetTop;temp = n.offsetLeft;temp = n.offsetWidth;temp = n.offsetHeight;temp = n.scrollTop;temp = n.scrollHeight;alert(temp);



repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲染。reflow(渲染),与repaint区别就是他会影响到dom的结构渲染,同时他会触发repaint,他会改变他本身与所有父辈元素(祖先),这种开销是非常昂贵的,导致性能下降是必然的,页面元素越多效果越明显。何时发生:1. DOM元素的添加、修改(内容)、删除( Reflow + Repaint)2. 仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)3. 应用新的样式或者修改任何影响元素外观的属性4. Resize浏览器窗口、滚动页面5. 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、 getComputedStyle()、currentStyle(in IE)) 如何避免:1. 先将元素从document中删除,完成修改后再把元素放回原来的位置2. 将元素的display设置为”none”,完成修改后再把display修改为原来的值3. 如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入document   var fragment = document.createDocumentFragment();fragment.appendChild(document.createTextNode('keenboy test 111'));fragment.appendChild(document.createElement('br'));fragment.appendChild(document.createTextNode('keenboy test 222'));document.body.appendChild(fragment);4. 集中修改样式   4.1尽可能少的修改元素style上的属性   4.2尽量通过修改className来修改样式  4.3通过cssText属性来设置样式值    element.style.width=”80px”;  //reflow    element.style.height=”90px”; //reflow    element.style.border=”solid 1px red”; //reflow    以上就产生多次reflow,调用的越多产生就越多    element.style.cssText=”width:80px;height:80px;border:solid 1px red;”; //reflow   4.4缓存Layout属性值     var left=elem.offsetLeft; 多次使用left也就产生一次reflow  4.5设置元素的position为absolute或fixed    元素脱离标准流,也从DOM树结构中脱离出来,在需要reflow时只需要reflow自身与下级元素  4.6尽量不要用table布局    table元素一旦触发reflow就会导致table里所有的其它元素 reflow。在适合用table的场合,可以设置table-layout为auto或fixed,这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围  4.7避免使用expression,他会每次调用都会重新计算一遍(包括加载页面)参考:Yahoo! 性能工程师 Nicole Sullivan 在最新的文章 《Reflows & Repaints: CSS Performance making your JavaScript slow?》

0 0
原创粉丝点击