Skip to main content

Reflow & Repaint

根据渲染树布局,计算 CSS 样式,即每个节点在页面中的大小和位置等几何信息。HTML 默认是流式布局的,CSS 和 JS 会打破这种布局,改变 DOM 的外观样式以及大小和位置。这时就要提到两个重要概念:Reflow 和 Repaint。

Reflow/Layout: 意味着元件的几何尺寸变了,我们需要重新验证并计算渲染树。是渲染树的一部分或全部发生了变化。这就是 Reflow,或是 Layout。 Repaint:屏幕的一部分重画,不影响整体布局,比如某个 CSS 的背景色变了,但元素的几何尺寸和位置不变。

  1. 常见引起重排属性和方法

任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。

添加或者删除可见的 DOM 元素;

  • 元素尺寸改变——边距、填充、边框、宽度和高度
  • 内容变化,比如用户在 input 框中输入文字
  • 浏览器窗口尺寸改变——resize 事件发生时
  • 计算 offsetWidth 和 offsetHeight 属性
  • 设置 style 属性的值
常见引起表格重排属性和方法
widthheightmarginpadding
displayborderpositionoverflow
clientWidthclientHeightclientTopclientLeft
offsetWidthoffsetHeightoffsetTopoffsetLeft
scrollWidthscrollHeightscrollTopscrollLeft
scrollIntoView()scrollTo()getComputedStyle()
getBoundingClientRect()scrollIntoViewIfNeeded()
  1. 常见引起重绘的属性和方法
常见引起重绘的属性和方法
colorborder-stylevisibilitybackground
text-decorationbackground-imagebackground-positionbackground-repeat
outline-coloroutlineoutline-styleborder-radius
outline-widthbox-shadowbackground-size

下面例子中,触发了几次回流和重绘?

var s = document.body.style;
s.padding = '2px'; // 回流+重绘
s.border = '1px solid red'; // 再一次 回流+重绘
s.color = 'blue'; // 再一次重绘
s.backgroundColor = '#ccc'; // 再一次 重绘
s.fontSize = '14px'; // 再一次 回流+重绘
// 添加node,再一次 回流+重绘
document.body.appendChild(document.createTextNode('abc!'));
  1. 如何减少回流、重绘
  • 使用 transform 替代 top
  • 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
  • 不要把节点的属性值放在一个循环里当成循环里的变量。
for (let i = 0; i < 1000; i++) {
// 获取 offsetTop 会导致回流,因为需要去获取正确的值
console.log(document.querySelector('.test').style.offsetTop);
}
  • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局
  • 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame
  • CSS 选择符从右往左匹配查找,避免节点层级过多
  • 将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层。

有些情况下,比如修改了元素的样式,浏览器并不会立刻 reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。有些情况下,比如 resize 窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。