Reflow & Repaint
根据渲染树布局,计算 CSS 样式,即每个节点在页面中的大小和位置等几何信息。HTML 默认是流式布局的,CSS 和 JS 会打破这种布局,改变 DOM 的外观样式以及大小和位置。这时就要提到两个重要概念:Reflow 和 Repaint。
Reflow/Layout: 意味着元件的几何尺寸变了,我们需要重新验证并计算渲染树。是渲染树的一部分或全部发生了变化。这就是 Reflow,或是 Layout。 Repaint:屏幕的一部分重画,不影响整体布局,比如某个 CSS 的背景色变了,但元素的几何尺寸和位置不变。
- 常见引起重排属性和方法
任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。
添加或者删除可见的 DOM 元素;
- 元素尺寸改变——边距、填充、边框、宽度和高度
- 内容变化,比如用户在 input 框中输入文字
- 浏览器窗口尺寸改变——resize 事件发生时
- 计算 offsetWidth 和 offsetHeight 属性
- 设置 style 属性的值
常见引起表格重排属性和方法 | |||
---|---|---|---|
width | height | margin | padding |
display | border | position | overflow |
clientWidth | clientHeight | clientTop | clientLeft |
offsetWidth | offsetHeight | offsetTop | offsetLeft |
scrollWidth | scrollHeight | scrollTop | scrollLeft |
scrollIntoView() | scrollTo() | getComputedStyle() | |
getBoundingClientRect() | scrollIntoViewIfNeeded() |
- 常见引起重绘的属性和方法
常见引起重绘的属性和方法 | |||
---|---|---|---|
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-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!'));
- 如何减少回流、重绘
- 使用 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。