重绘和重排

页面渲染过程

aa

  1. 解析 HTML 标记并构建 DOM 树
  2. 样式计算
  3. 布局定位
  4. 图层分层
  5. 图层绘制
  6. 合成显示

在 css 属性改变时,重渲染会分为回流重绘直接合成三种情况,分别对应从布局定位图层绘制合成显示开始,继续后面的流程

元素的 CSS 属性具体发生什么变化,则决定属于什么情况

  • 回流(重排):元素的位置、大小发生变化导致其他节点联动,需要重新计算布局
  • 重绘: 修改不影响布局的属性,如背景色、字体颜色等
  • 直接合成: transformopacity、修改,只需要将多个图层再次合并,再生成位图,最终显示在屏幕上

触发时机

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。

回流的触发时机

  • 添加或删除 「可见的 DOM 元素」
  • 元素的 「位置」 发生变化
  • 元素的 「尺寸」 发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  • 页面一开始渲染的时候(这避免不了)
  • 浏览器的 「窗口尺寸变化」(因为回流是根据视口的大小来计算元素的位置和大小的) 获取一些特定属性的值
    • offsetTopoffsetLeftoffsetWidthoffsetHeight
    • scrollTopscrollLeftscrollWidthscrollHeight
    • clientTopclientLeftclientWidthclientHeight
    • 这些属性有一个共性,就是需要通过 「即时计算」 得到。因此浏览器为了获取这些值,也会进行回流。

重绘的触发时机

提示

触发回流一定会触发重绘

  • 「颜色」的修改
  • 「文本方向」的修改
  • 「阴影」的修改

浏览器的优化机制

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会 「通过队列存储重排操作并批量执行来优化重排过程」。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

当你获取布局信息的操作的时候,会 「强制队列刷新」,例如 offsetTop 等方法都会返回最新的数据。

因此浏览器不得不清空队列,触发回流重绘来返回正确的值

减少回流

  1. 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响
  2. 使用 css3 「硬件加速」,可以让 transformopacityfilters 这些动画不会引起回流重绘
  3. 在使用 JavaScript **「动态插入多个节点」**时, 可以使用 DocumentFragment.创建后一次插入.
  4. 通过设置元素属性 display: none,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作
贡献者: huxiguo