页面优化---减少页面重绘和回流
触发回流:
1.调整窗口大小(Resizing the windown);
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 pseduo class of a silibing));
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)。
如何减少回流和重绘
1.直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器);
// 不好的写法 var left = 1; var top = 1; el.style.left = left + "px"; el.style.top = top + "px";// 比较好的写法 el.className += " className1"; // 比较好的写法 el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
2.让操作的元素进行“离线处理”,处理完后一次更新;
使用DocumentFragment进行缓存操作,引发一次回流和重绘;
使用display:none属性,只引发两次回流和重绘;
使用cloneNode(true or false)和replaceChild技术,引发一次回流和重绘。
3.不要经常访问会引起浏览器flush队列的属性,如果你确定要缓存,利用缓存;
// 不好的写法 for(循环) { el.style.left = el.offsetLeft + 5 + "px"; el.style.top = el.offsetTop + 5 + "px"; } // 这样写好点 var left = el.offsetLeft, top = el.offsetTop, s = el.style; for (循环) { left += 10; top += 10; s.left = left + "px"; s.top = top + "px"; }
4.让元素脱离动画流,减少回流的render tree的规模;
$("#block1").animate({left:50}); $("#block2").animate({marginLeft:50});
5.尽可能在DOM树的最末端改变class(可限制回流的范围);
6.避免设置多层内联样式(将样式合并在一个外部类,仅产生一次回流);
7.动画效果应用到position属性为absolute或fixed的元素上(动画效果应用到position属性为absolute或fixed的元素上,它们不影响其他元素的布局,所它他们只会导致重新绘制,而不是一个完整回流。这样消耗会更低。);
8.牺牲平滑度换取速度(Opera还建议我们牺牲平滑度换取速度,其意思是指您可能想每次1像素移动一个动画,但是如 果此动画及随后的回流使用了 100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导 致CPU在较慢的机器和移动设备中抖动。);
9.避免使用table数据(在布局完全建立之前,table经常需要多个关口,因为table是个和罕见的可以影响在它们之前已经进入的DOM元素的显示的元素。);
10.避免使用css的JavaScript表达式(因为他们每次重新计算文档,或部分文档、回流。正如我们从所有的很多事情看到的:引发回流,它可以每秒产生成千上万次。)。
实例测试一:
测试代码不改变元素的规则,大小,位置。只改变颜色,所以不存在回流,仅测试重绘,代码如下:
<body> <script type="text/javascript"> var s = document.body.style; var computed; if (document.body.currentStyle) { computed = document.body.currentStyle; } else { computed = document.defaultView.getComputedStyle(document.body, ''); } function testOneByOne(){ s.color = 'red';; tmp = computed.backgroundColor; s.color = 'white'; tmp = computed.backgroundImage; s.color = 'green'; tmp = computed.backgroundAttachment; } function testAll() { s.color = 'yellow'; s.color = 'pink'; s.color = 'blue'; tmp = computed.backgroundColor; tmp = computed.backgroundImage; tmp = computed.backgroundAttachment; } </script> color test <br /> <button onclick="testOneByOne()">Test One by One</button> <button onclick="testAll()">Test All</button> </body>
实例测试二:
跟第一次测试的代码很类似,但加上了对layout的改变,为的是测试回流。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1 /DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> <script type="text/javascript"> var s = document.body.style; var computed; if (document.body.currentStyle) { computed = document.body.currentStyle; } else { computed = document.defaultView.getComputedStyle(document.body, ''); } function testOneByOne(){ s.color = 'red'; s.padding = '1px'; tmp = computed.backgroundColor; s.color = 'white'; s.padding = '2px'; tmp = computed.backgroundImage; s.color = 'green'; s.padding = '3px'; tmp = computed.backgroundAttachment; } function testAll() { s.color = 'yellow'; s.padding = '4px'; s.color = 'pink'; s.padding = '5px'; s.color = 'blue'; s.padding = '6px'; tmp = computed.backgroundColor; tmp = computed.backgroundImage; tmp = computed.backgroundAttachment; } </script> color test <br /> <button onclick="testOneByOne()">Test One by One</button> <button onclick="testAll()">Test All</button> </body> </html>
避免回流和重绘的次数可从代码的角度来实现性能优化,因此我们在写代码时应尽量使用上诉方法来减少网页回流和重绘的次数。