【前端工程师手册】学习回流和重绘(reflow和repaint)

478 阅读2分钟

浏览器的大概工作流程

以普通的HTML页面为例:

  1. 解析HTML文档,生成dom树
  2. 解析css产生css规则树
  3. 解析JavaScript,通过DOM-API来操作dom树和css规则树
  4. 通过dom树和css规则树来构造渲染树(rendering tree)
  5. 调用操作系统的GUI接口画页面

回流(reflow)和重绘(repaint)

回流:

元素的大小尺寸、位置发生变化时,会重新计算渲染树,页面要进行重新排版工作,这个过程即是回流。<br>

重绘:

元素做了一些不影响排版的改变,比如背景色、下划线等等,只需要重新绘制的过程,叫做重绘。

显然回流带来的代价大于重绘,因为重绘仅仅是重新画一遍元素而已,但是重绘是重新计算+重新画

回流的原因:

  • Initial。网页初始化的时候。
  • Incremental。一些Javascript在操作DOM Tree时。
  • Resize。其些元件的尺寸变了
  • StyleChange。如果CSS的属性发生变化了。
  • Dirty。几个Incremental的reflow发生在同一个元素的子树上。 更具体的说,就是这些常见的操作会引起回流:
  1. 调整窗口大小
  2. 字体大小
  3. 样式表变动
  4. 元素内容变化,尤其是输入控件
  5. CSS伪类激活,在用户交互过程中发生
  6. DOM操作,DOM元素增删、修改
  7. width, clientWidth, scrollTop等布局宽高的计算 **ps:**但是浏览器并不会在我们一进行上面的操作就进行回流,浏览器会积攒一批reflow然后一起进行回流,不过有的操作会让浏览器立马进行回流,比如resize窗口,改变了页面默认的字体,或者说获取以下这些值:
  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • IE中的 getComputedStyle(), 或 currentStyle

如何减少reflow和repaint

  1. 避免频繁的修改样式,可以将要修改的多个样式定义为一个class类,然后将类名一次赋值即可
  2. 把dom离线操作:
    • 使用documentFragment 对象在内存里操作DOM
    • 先把DOM给display:none(有一次reflow),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。
    • clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下
  3. 不要把DOM结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。
  4. 为动画的HTML元件使用fixed或absoult的position,那么修改他们的CSS是不会reflow的,因为脱离了文档流

参考

减少重排与重绘

浏览器的渲染原理简介