回流与重绘

来源:互联网 发布:手机微信连不上网络 编辑:程序博客网 时间:2024/04/29 08:40
回流(reflow):当render树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建时称为回流。如改变某个元素的margin,那么其后的元素需要跟着改变。render树需要重新组装。重绘(repaint):元素的外观、风格改变并且不会影响页面布局时称为重绘。如改变元素的背景颜色,字体颜色等。注:改变文字大小在一定程度上可能会改变页面的结构,撑破原有的容器。dom树:包含元素,即html标签;render树:不仅包含html元素,还能识别样式,即每个节点都有对应的样式修饰。但其不包含隐藏的节点(displaynonehead节点),包含visibility:hidden元素,因为设置该样式的元素会影响布局。
回流发生的场景:1.添加或者删除可见的DOM元素;2.元素位置改变;3.元素尺寸改变——边距、边框、填充、宽度和高度;4.内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;5.页面渲染初始化;6.浏览器窗口尺寸改变——resize事件发生时.
例:/*回流必将引起重绘,而重绘不一定引起回流。*/var s = document.body.style;s.padding = "2px"; // 回流+重绘s.border = "1px solid red"; // 再一次 回流+重绘s.color = "blue"; // 再一次重绘s.backgroundColor = "#ccc"; // 再一次 重绘s.fontSize = "14px"; // 再一次 回流+重绘// 添加node,再一次 回流+重绘document.body.appendChild(document.createTextNode('abc!'));

因此回流比重绘的代价更高,回流的花销与render tree中有多少节点需要重建有关。

浏览器自身的优化:浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。但当你请求向浏览器请求一些 style信息的时候,为了提供更准确的值。浏览器会提前flush队列。如:1. offsetTop, offsetLeft, offsetWidth, offsetHeight;2. scrollTop/Left/Width/Height;3. clientTop/Left/Width/Height;4. width,height;5. window.getComputedStyle("对象")["属性名"]或者IE的 obj.currentStyle.属性名;

减少回流与重绘的方式:

1.避免逐项更改样式,最好一次性更改style属性,即先定义一个类,为其设置样式,再将该类添加到指定的元素中去。

如:<style>.new{    background-color: pink;}</style><script>var body = document.body;body.className += " new";/*注意此处有一个空格*/</script>

2.在一个设置display: none的元素上进行操作,操作完后让其显示。因为在display: none元素上做的操作不会引起回流与重绘。

3.绝对定位具有复杂动画的元素,使其脱离文档流,不会引起其父元素及后继元素的大量回流。

4.不要多次或循环读取使浏览器提前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"; }