# 回流和重绘

回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

重绘:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。 回流必将引起重绘,而重绘不一定会引起回流。

我们需要明白,页面若发生回流则需要付出很高的代价,当页面布局和几何属性改变时就需要回流。下述情况会发生浏览器回流:

  1. 添加或者删除可见的DOM元素;
  2. 元素位置改变;
  3. 元素尺寸改变——边距、填充、边框、宽度和高度
  4. 内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变;
  5. 页面渲染初始化;
  6. 浏览器窗口尺寸改变——resize事件发生时;

优化方案: 减少回流、重绘其实就是需要减少对render tree的操作(合并多次多DOM和样式的修改),并减少对一些style信息的请求,尽量利用好浏览器的优化策略。

  1. 直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)
  2. 让要操作的元素进行”离线处理”,处理完后一起更新
  3. 不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存
  4. 让元素脱离动画流,减少回流的Render Tree的规模

那如果我们使用属性又有那些可替换的属性可以优化回流与重绘呢,一共有一下9点:

  1. 用transform 代替 top,left ,margin-top, margin-left... 这些位移属性
  2. 用opacity 代替 visibility,但是要同时有translate3d 或 translateZ 这些可以创建的图层的属性存在才可以阻止回流 但是第二点经过我的实验,发现如果不加 transform: translateZ(0) 配合opacity的话还是会产生回流的,而只用visibility 就只会产生重绘不会回流 而 opacity 加上 transform: translateZ/3d 这个属性之后便不会发生回流和重绘了
  3. 不要使用 js 代码对dom 元素设置多条样式,选择用一个 className 代替之。
  4. 如果确实需要用 js 对 dom 设置多条样式那么可以将这个dom 先隐藏,然后再对其设置
  5. 不要在循环内获取dom 的样式例如:offsetWidth, offsetHeight, clientWidth, clientHeight... 这些。浏览器有一个回流的缓冲机制,即多个回流会保存在一个栈里面,当这个栈满了浏览器便会一次性触发所有样式的更改且刷新这个栈。但是如果你多次获取这些元素的实际样式,浏览器为了给你一个准确的答案便会不停刷新这个缓冲栈,导致页面回流增加。 所以为了避免这个问题,应该用一个变量保存在循环体外。
  6. 不要使用table 布局,因为table 的每一个行甚至每一个单元格的样式更新都会导致整个table 重新布局
  7. 动画的速度按照业务按需决定
  8. 对于频繁变化的元素应该为其加一个 transform 属性,对于视频使用video 标签
  9. 必要时可以开启 GPU 加速,但是不能滥用