Reflow是载入内容树(在HTML中就是DOM树)和创建或更新frame结构的响应的一种过程。本文旨在讨论几种常见的reflow优化方案,并尝试得到新的方法。
目录[-]
前言:什么是重绘与回流?
重绘(repaints)是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。
回流(reflow)是更明显的一种改变,可以理解为渲染树需要重新计算。
1,为什么我们
讨厌回流?
回流这家伙,只要出现,就会重新对DOM树进行渲染,而大多数时候,这种全局性的渲染是无必要的。就像你花钱买了门票去景区玩,进门查票,出门查票,都可以理解是吧?但是你吃饭也查票,上厕所也查票,就完全没必要了对吧?浏览器虽然不是人,但是没准也有脾气,回流的次数多了,性能跟不上了,就是立马崩溃掉也是有可能的事儿。回流=查票
2,我们怎样
搞定回流?
2.1 CSS中的定位、隐藏
前面说到,回流的危害在于重新对DOM树进行渲染,那么,脱离文档流之后,进行的任何操作,都不会造成回流了!如果有需要经常进行复杂操作的地方,不妨使用position:absolute/fixed定位;或者是display:none,使之脱离文档流后进行操作,操作完成后再进入到文档流之中。
2.2 CSS中的顽固属性
以下这些属性,只要是改动了他们的值,就会造成回流,建议将他们合并到一起操作,可以减少回流的次数。这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、clientWidth、clientHeight;getComputedStyle() 、currentStyle()。
2.3 Javascript控制样式的最优解
我们在利用Javascript进行样式控制的时候,不妨只是改变被控制者的class,而非在函数内部直接修改具体的样式。因为浏览器在我们用Javascript修改每一个具体样式的时候,都会进行一次重绘,如果是修改了2.2中的顽固属性,还会进行回流,这给浏览器造成了巨大的负担。例如,我们需要用这样的代码:
01 坏代码:
02 function selectAnchor(element){
03 var changeDiv = document.getElementById(element);
04 changeDiv.style.color = ‘#093′;
05 changeDiv.style.background = ‘#eee’;
06 changeDiv.style.height = ’200px’;
07 }
08
09 好代码:
10 CSS:
11 changeDiv {
12 background: #eee;
13 color: #093;
14 height: 200px;
15 }
16 JavaScript:
17 function selectAnchor(element) {
18 document.getElementById(element).className = ‘changeDiv’;
19 }
举个形象的栗子,既然QQ的账号和密码可以同时登陆邮箱,微信和微博,我们不会单独去修改后者的密码,而只用修改QQ密码,就可以达到所有的目的
2.4 Javascript添加多个元素
Javascript添加多个元素造成的回流其实更恐怖,插入,删除,样式变化,每一项都能造成一次DOM树的重新渲染。而我们的做法和2.3相似,先把这些元素都集合在一个方法之内,再调用出来,就能有效的减少回流了。比如我们需要控制一个表格的隔行变色:回流
一般的做法是什么呢?一个遍历下去,全搞定
1 坏代码:
2 function updateAllAnchors(element, anchorClass) {
3 var anchors = element.getElementsByTagName("tr");
4 for (var i = 0, length = anchors.length; i < length; i ++) {
5 anchors[i].className = anchorClass;
6 }
7 }
这样做的坏处是什么呢?表格有10行,就要进行10次回流,20行,30行?这样解决:
01 好代码:
02 //首先把表格删除,放到DOM树外部操作
03 function removeToInsertLater(element) {
04 var parentNode = element.parentNode;
05 var nextSibling = element.nextSibling;
06 parentNode.removeChild(element);
07 return function() {
08 if (nextSibling) {
09 parentNode.insertBefore(element, nextSibling);
10 } else {
11 parentNode.appendChild(element);
12 }
13 }
14 }
15 //然后调用它
16 function updateAllAnchors(element, anchorClass) {
17 var insertFunction = removeToInsertLater(element);
18 var anchors = element.getElementsByTagName("a");
19 for (var i = 0, length = anchors.length; i < length; i ++) {
20 anchors[i].className = anchorClass;
21 }
22 insertFunction();
23 }
目录[-]
前言:什么是重绘与回流?
重绘(repaints)是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。
回流(reflow)是更明显的一种改变,可以理解为渲染树需要重新计算。
1,为什么我们
讨厌回流?
回流这家伙,只要出现,就会重新对DOM树进行渲染,而大多数时候,这种全局性的渲染是无必要的。就像你花钱买了门票去景区玩,进门查票,出门查票,都可以理解是吧?但是你吃饭也查票,上厕所也查票,就完全没必要了对吧?浏览器虽然不是人,但是没准也有脾气,回流的次数多了,性能跟不上了,就是立马崩溃掉也是有可能的事儿。回流=查票
2,我们怎样
搞定回流?
2.1 CSS中的定位、隐藏
前面说到,回流的危害在于重新对DOM树进行渲染,那么,脱离文档流之后,进行的任何操作,都不会造成回流了!如果有需要经常进行复杂操作的地方,不妨使用position:absolute/fixed定位;或者是display:none,使之脱离文档流后进行操作,操作完成后再进入到文档流之中。
2.2 CSS中的顽固属性
以下这些属性,只要是改动了他们的值,就会造成回流,建议将他们合并到一起操作,可以减少回流的次数。这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、clientWidth、clientHeight;getComputedStyle() 、currentStyle()。
2.3 Javascript控制样式的最优解
我们在利用Javascript进行样式控制的时候,不妨只是改变被控制者的class,而非在函数内部直接修改具体的样式。因为浏览器在我们用Javascript修改每一个具体样式的时候,都会进行一次重绘,如果是修改了2.2中的顽固属性,还会进行回流,这给浏览器造成了巨大的负担。例如,我们需要用这样的代码:
01 | 坏代码: |
02 | function selectAnchor(element){ |
03 | var changeDiv = document.getElementById(element); |
04 | changeDiv.style.color = ‘#093′; |
05 | changeDiv.style.background = ‘#eee’; |
06 | changeDiv.style.height = ’200px’; |
07 | } |
08 |
09 | 好代码: |
10 | CSS: |
11 | changeDiv { |
12 | background: #eee; |
13 | color: #093; |
14 | height: 200px; |
15 | } |
16 | JavaScript: |
17 | function selectAnchor(element) { |
18 | document.getElementById(element).className = ‘changeDiv’; |
19 | } |
举个形象的栗子,既然QQ的账号和密码可以同时登陆邮箱,微信和微博,我们不会单独去修改后者的密码,而只用修改QQ密码,就可以达到所有的目的
2.4 Javascript添加多个元素
Javascript添加多个元素造成的回流其实更恐怖,插入,删除,样式变化,每一项都能造成一次DOM树的重新渲染。而我们的做法和2.3相似,先把这些元素都集合在一个方法之内,再调用出来,就能有效的减少回流了。比如我们需要控制一个表格的隔行变色:回流
一般的做法是什么呢?一个遍历下去,全搞定
1 | 坏代码: |
2 | function updateAllAnchors(element, anchorClass) { |
3 | var anchors = element.getElementsByTagName("tr"); |
4 | for (var i = 0, length = anchors.length; i < length; i ++) { |
5 | anchors[i].className = anchorClass; |
6 | } |
7 | } |
这样做的坏处是什么呢?表格有10行,就要进行10次回流,20行,30行?这样解决:
01 | 好代码: |
02 | //首先把表格删除,放到DOM树外部操作 |
03 | function removeToInsertLater(element) { |
04 | var parentNode = element.parentNode; |
05 | var nextSibling = element.nextSibling; |
06 | parentNode.removeChild(element); |
07 | return function() { |
08 | if (nextSibling) { |
09 | parentNode.insertBefore(element, nextSibling); |
10 | } else { |
11 | parentNode.appendChild(element); |
12 | } |
13 | } |
14 | } |
15 | //然后调用它 |
16 | function updateAllAnchors(element, anchorClass) { |
17 | var insertFunction = removeToInsertLater(element); |
18 | var anchors = element.getElementsByTagName("a"); |
19 | for (var i = 0, length = anchors.length; i < length; i ++) { |
20 | anchors[i].className = anchorClass; |
21 | } |
22 | insertFunction(); |
23 | } |
本文探讨了网页渲染过程中回流(reflow)的概念及其对用户体验的影响,并提供了几种减少回流次数的方法,包括使用CSS定位、合并顽固属性的更改、通过JavaScript修改class而非内联样式以及批量处理DOM操作。

的几种方法&spm=1001.2101.3001.5002&articleId=28440901&d=1&t=3&u=2068c69bd7734791a92da8b234d1f927)
10万+

被折叠的 条评论
为什么被折叠?



