页面渲染性能控制重绘与回流

6次阅读

共计 1426 个字符,预计需要花费 4 分钟才能阅读完成。

浏览器解析代码过程

页面的显示过程分为以下几个阶段:

  1. 生成 DOM 树(包括 display:none 的节点)
  2. 在 DOM 树的基础上根据节点的集合属性 (margin,padding,width,height 等) 生成 render 树(不包括 display:none,head 节点,但是包括 visibility:hidden 的节点)
  3. 在 render 树的基础上继续渲染颜色背景色等样式

reflow: 当 render 树的一部分或者全部因为大小边距等问题发生改变而需要重建的过程,叫做回流
repaint: 当诸如颜色背景等不会引起页面布局变化,而只需要重新渲染的过程叫做重绘

通过上述定义,可以很明显看出,重绘的代价要比回流小。重绘只涉及样式的改变,不涉及到布局。重绘就好像给人染了一个头发,而回流相当于给人做了一次整形手术

什么会引起回流

  1. 页面渲染初始化
  2. DOM 结构变化,脸上整得亲妈都认不出来了,所以会引发回流
  3. render 树变化,比如减少了 padding,增加 border 等等,改变页面布局了
  4. 窗口 resize 事件触发
  5. 最复杂的一种:获取某些属性,引发回流 很多浏览器会对回流做优化,他会等到足够数量的变化发生,在做一次批处理回流。
    但是除了 render 树的直接变化。
    当获取一些属性时,浏览器为了获得正确的值也会触发回流。这样就使得浏览器的优化失效了 这些属性包括

       offsetTop,     offsetLeft,     offsetWidth,     offsetHeight
       scrollTop/Left/Width/Height,
       clientTop/Left/Width/Height,
       width,height
       调用了 getComputedStyle(), 或者 IE 的 currentStyle
    

这段儿代码是抄的,哈哈,大概解释一下样式改变引起的重绘和回流

var s = document.body.style;

s.padding = "2px"; // 回流 + 重绘

s.border = "1px solid red"; // 再一次 回流 + 重绘

s.color = "blue"; // 再一次重绘

s.backgroundColor = "#ccc"; // 再一次 重绘

s.fontSize = "14px"; // 再一次 回流 + 重绘, 没想到吧,改变字体大小也会回流

document.body.appendChild(document.createTextNode('abc!'));  // 添加 node,再一次 回流 + 重绘

可以看出,回流一定伴随着重绘,而重绘却可以单独出现

回流对性能产生了一定的影响,尽管浏览器机智地帮我们进行了批处理,但是仍然存在着上述诸多阔怕的属性,一获取就回流。怎么解决?

减少回流

  1. 避免逐项更改样式。最好一次性更改 style 属性,或者将样式列表定义为 class 并一次性更改 class 属性。
  2. 避免循环操作 DOM。创建一个 documentFragment 或 div,在它上面应用所有 DOM 操作,最后再把它添加到 window.document。
  3. 避免多次读取 offsetLeft 等属性。无法避免则将它们缓存到变量。
  4. 将复杂的元素绝对定位或固定定位,使它脱离文档流。否则回流代价十分高

display:none 和 visibility:hidden 会产生回流与重绘

display:none 指的是元素完全不陈列出来,不占据空间,涉及到了 DOM 结构,故产生 reflow 与 repaint
visibility:hidden 指的是元素不可见但存在,保留空间,不影响结构,故只产生 repaint

正文完
 0