# 重绘和回流

面试中经常被问到什么是回流和重绘,所以在这里做一个总结。

# 什么是重绘(repaints)

当一个元素的外观的可见性 visibility 发生改变的时候,重绘(repaint)也随之发生,但是不影响布局。

会触发重绘的属性包括:outline, visibility, color, background color, translate 等。

# 什么是回流(reflow)

元素的规模尺寸,布局,隐藏等改变从而影响到页面布局的变化时就会触发回流。一个元素的回流会导致其所有子元素以及 DOM 中紧随其后的祖先元素的随后的回流。

注意:回流必将引起重绘,而重绘不一定会引起回流。

# 导致回流的原因

  • 页面首次渲染
  • 调整窗口大小
  • 改变字体
  • 增加或者移除样式表
  • 内容变化,比如用户在 input 框中输入文字
  • 激活 CSS 伪类,比如 :hover (IE 中为兄弟结点伪类的激活)
  • 操作 class 属性
  • 脚本操作 DOM
  • 计算 offsetWidth 和 offsetHeight 属性
  • 设置 style 属性的值

因为现代浏览器为了减少重绘回流对性能的影响,所以做了一些优化操作,会把引起回流、重绘的操作放入到一个队列中,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会 flush 队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。

但是当 JS 获取以下 style 信息时,浏览器会立即 flush 队列,触发回流:

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • width、height
  • getComputedStyle()
  • getBoundingClientRect()

# 如何避免回流

如何避免回流的产生可以从 CSS 和 JS 两个方面进行优化

# CSS 优化

  • 如果想设定元素的样式,通过改变元素的 class 名 (尽可能在 DOM 树的最末端)
  • 避免设置多项内联样式
  • 应用元素的动画,使用 position 属性的 fixed 值或 absolute 值
  • 权衡平滑和速度
  • 避免使用 table 布局
  • 避免使用 CSS 的 JavaScript 表达式 (仅 IE 浏览器)

# JS 优化

  • 避免频繁操作样式
  • 避免频繁操作 DOM
  • 避免频繁读取会引发回流/重绘的属性

参考链接: