一次性弄懂回流和重绘

回流(Reflow)重绘(Repaint)

何时会触发回流或重绘呢?

当咱们对dom 进行修改当时候会引起它外观(样式)上的改变时,就会触发回流或重绘。
这个过程本质上仍是由于咱们对 DOM 的修改触发了渲染树(Render Tree)的变化所致使的
clipboard.png浏览器

咱们回顾一下浏览器渲染页面的流程

1.根据 HTML 结构生成 DOM 树
2.根据 CSS 生成 CSSOM
3.将 DOM 和 CSSOM 整合造成 RenderTree
4.根据 RenderTree 开始渲染和展现
5.遇到<script>时,会执行并阻塞渲染缓存

  • 回流: 当咱们对dom进行修改当时候,而且致使页面几何尺寸发生变化当时候(好比修改元素的宽、高或隐藏元素等),浏览器须要从新去计算元素当几何属性,而且同时会影响到其余元素当几何属性,而后将从新计算出来的结果绘制出来,这个过程就叫回流也叫重排。
  • 重绘:当咱们对 DOM 的修改致使了样式的变化、却并未影响其几何属性(好比修改了颜色或背景色)时,浏览器不需从新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫作重绘。

因此由此来看 重绘不必定致使回流,回流必定会致使重绘 前面咱们说回流和重绘是会对dom进行修改,会消耗性能,因此咱们要尽量减小回流和重绘的次数。dom

怎么减小回流和重绘呢?

要减小回流和重绘的发生,咱们得知道那些操做会致使,布局

回流

1.改变dom元素的几何属性
常见的几何属性有 width、height、padding、margin、left、top、border 等等。此处再也不给你们一一列举。有的文章喜欢罗列属性表格,但我相信我今天列出来你们也不会看、看了也记不住(由于太多了)。我本身也不会去记这些——其实确实不必记,️一个属性是否是几何属性、会不会致使空间布局发生变化,你们写样式的时候彻底能够经过代码效果看出来。
2.改变dom树的结构
主要指的是增长或减小dom节点,移动等操做。
3.获取一些特定属性的值
当你要用到像这样的属性:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 时,你就要注意了!性能

“像这样”的属性,究竟是像什么样?——这些值有一个共性,就是须要经过即时计算获得。所以浏览器为了获取这些值,也会进行回流。spa

除此以外,当咱们调用了 getComputedStyle 方法,或者 IE 里的 currentStyle 时,也会触发回流。原理是同样的,都为求一个“即时性”和“准确性”。code

重绘

回流比重绘更加消耗性能,付出的代价更高队列

那如何避免回流和重绘

1.避免逐条改变样式,使用类名去合并样式ip

const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'

将这段代码用 类名去合并get

.basic_style {
  width: 100px;
  height: 200px;
  border: 10px solid red;
  color: red;
}
const container = document.getElementById('container')
container.classList.add('basic_style')

2.将 DOM “离线”

let container = document.getElementById('container')
container.style.display = 'none'
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'
...(省略了许多相似的后续操做)
container.style.display = 'block'

Flush 队列

继续用上面的代码来讲明这个问题

const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'

从这段代码中发生了几回回流与重绘呢?在这里改变了几何属性的有width, height, border。改变颜色的red,因此致使了三次回流和一次重绘,一眼看过去是很正确的,实际上是忽略了浏览器自身:并无那么简单!这段代码实际上只进行了一次回流和一次重绘,为何和咱们开始想的不同呢?由于现代浏览器是很聪明的。浏览器本身也清楚,若是每次 DOM 操做都即时地反馈一次回流或重绘,那么性能上来讲是扛不住的。因而它本身缓存了一个 flush 队列,把咱们触发的回流与重绘任务都塞进去,待到队列里的任务多起来、或者达到了必定的时间间隔,或者“不得已”的时候,再将这些任务一口气出队。所以咱们看到,上面就算咱们进行了 4 次 DOM 更改,也只触发了一次 Layout 和一次 Paint。可是也有例外,由于有的时候咱们须要精确获取某些样式信息,下面这些:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 这些属性有很强的“即时性”。当咱们访问这些属性时,浏览器会为了得到此时此刻的、最准确的属性值,而提早将 flush 队列的任务出队——这就是所谓的“不得已”时刻。

相关文章
相关标签/搜索