# 重排与重绘

当元素的样式发生变化时,浏览器需要触发更新,重新绘制元素。这个过程中,有两种类型的操作,即重绘与重排

# 重排(reflow)

当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称之为 重排,此时,浏览器需要重新经过计算,计算后还需要重新布局页面,所以是比较重的操作

会触发重排的操作:

  • 页面首次渲染
  • 浏览器窗口大小改变
  • 元素尺寸、位置、内容发生改变
  • 元素字体大小变化
  • 添加或删除可见的 dom 元素
  • 激活 CSS 伪类(例如:hover)
  • 查询某些属性或调用某些方法
    • clientWidth、clientHeight、clientTop、clientLeft
    • offsetWidth、offsetHeight、offsetTop、offsetLeft
    • scrollWidth、scrollHeight、scrollTop、scrollLeft
    • getComputedStyle()
    • getBoundingClientRect()
    • scrollTo

# 重绘(repaint)

当元素样式的改变不影响布局时,浏览器会使用重绘对元素进行升级,由于此时只需要 UI 层面的重新像素绘制,因此损耗较小

# 如何避免触发重排和重绘

重排必会触发重绘,重绘不一定触发重排。重排代价较高,重绘开销较小

  • CSS

    • 避免使用 table 布局
    • 尽可能在 DOM 树的最末端改变 class
    • 避免使用多层内联样式
    • 避免使用 CSS 表达式(如:calc())
    • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上
    • CSS3 硬件加速(GPU 加速)
  • javascript

    • 避免频繁操作样式,可以汇总后统一 一次修改
    • 尽量使用 class 进行样式修改
    • 减少 dom 的增删次数,可以使用字符串或者 documentFragment 一次性插入
    • 极限优化时,可以将其样式修改为 display: none 后修改
    • 避免多次触发上面提到的那些会触发重排的方法,尽量用 变量存储
    • 对具有复杂动画的元素使用绝对定位,使其脱离文档流,否则会引起父元素及后续元素频繁回流