在之前的内容里已经说了浏览器是如何进行加载解析渲染的,接下来浏览器就要根据渲染树中各个节点的顺序,实际样式属性值进行布局啦,也称Layout或是Flow。
之前的部分一直在说css、dom树。这一回js该出场了。
前二者好不容易生成渲染树,进行布局啦,js就来开始鼓捣啦,先将一个元素改改宽度,然后就放大招来个display=none
,这些都在一定程度上改变着原有的布局位置。
js潇洒的走后,css、dom树又要忙叨起来,重新进行渲染布局。把他们两个这个过程就叫做reflow、repaint
科普一下这两只
repaint
当dom属性改变的仅是元素的外观,并不对布局造成影响,浏览器则会重新渲染这个元素,此过程称为repaint。
reflow
如果此次变化涉及元素的布局(width),则浏览器将抛弃原有属性值,进行重新渲染、布局。此过程称为reflow。
reflow必将引起repaint,repaint不一定会引起reflow,(repaint的概念范围应该包括reflow)
什么操作会引起浏览器进行reflow、repaint呢??
- DOM元素的添加、修改(内容)、删除。
- 隐藏元素。
display=none;//reflow
visibility=hidden;//repaint(需要css知识理解) - 应用新的样式,或是修改任何影响元素外观的属性。
- 用户的操作,如改变浏览器的大小,改变浏览器的字体大小等。
当然这时候浏览器也会出来干点事,不能这样被玩啊,,
很多浏览器会维护一个队列,把所有会引起repaint与reflow的操作放入这个队列,等队列中的操作累积了一定数量,或者到了一定的时间间隔,浏览器就会对这个队列进行批处理。这样就会让多次重绘变成一次。
但是呢,js也不会善罢甘休,
当js想要获得dom的一些属性时,浏览器为了给出最精确的值,会flush队列,及把缓冲区的数据强行输出。
像这些属性:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- width,height
How 如何才能尽可能的减少重绘的次数呢?
- 离线操作DOM
使用documentFragment(指文档碎片)进行缓存。然后将对dom节点的进行一次性的增加。
var oFragment = document.createDocumentFragment();
for(var i = 0 ; i < 10; i ++) {
var p = document.createElement("p");
var oTxt = document.createTextNode("段落" + i);
p.appendChild(oTxt);
oFragment.appendChild(p);
}
document.body.appendChild(oFragment);//一次性的添加子节点,只进行一次渲染刷新。
还有一种是如果你预先想在某个元素内进行dom节点的改动,你可以对这些元素的属性进行设置。
display=none;
-
集中修改样式
这个理解起来比较简单。看一下例子(网上还有前辈进行了测试,大赞)。
//逐一style
testNode.style.color=‘#eee’;
testNode.style.border=‘1px solid red’;
testNode.style.fontSize=‘20px’;
testNode.style.background=‘blue’;
testNode.style.width=“200px”;
//添加类名
.className1 {color:#eee;border:1px solid red;font-size:20px;background:blue;width:200px’;}
//...
testNode.className = ‘className1’;
//添加csstext
testNode.style.cssText = ‘color:#eee;border:1px solid red;font-size:20px;background:blue;width:200px’;
对比一下不同方法带来性能上的提升。所以建议大家采用增加样式类这种方式,进行集体修改样式。
缓存布局属性值
// 别这样写
for(循环) {� el.style.top = el.offsetTop + 5 + "px";�}
��// 这样写好点
�var top = el.offsetTop;//缓存属性值,不要动态获得这个值。
s = el.style;�
for(循环) {� top += 10;� s.top = top + "px";�}权衡动画帧宽
关于动画帧宽
动画帧宽英文
我理解了一下,帧指的是一个静止画面,在网页动画里,这应该是界面内元素拥有的一组静态属性值时的界面。帧宽,两个界面之间的时间,可以理解为界面属性值改变的时间长度。即setinterval的时间值,而显示屏有自己的刷新频率,大概是在16.667ms,浏览器的repaint的时间是1ms。权衡一下设置的setinterval的时间值,使之尽可能与显示频的时间吻合,以减少重绘次数?这一点我说的不太肯定,得多看点资料才能肯定。
还有一个被忽略的元素<img>
,
遍历dom树时遇到这个标签,浏览器会发出一个异步请求,然后继续渲染dom树的其他节点。
但是可想而知,当图片资源获得后,又会改变原有的布局。
所以我们在为网页添加图片时,记得设置width与height属性。这样可以预先设置布局。
之后就是绘制啦,,
这就依靠浏览器的native GUI(这是浏览器的一个组成部分)啦
参考资源:
浅析浏览器解析和渲染
一次性处理添加节点的操作