资料

你真的了解回流和重绘吗 - SegmentFault 思否

回流与重绘 - 掘金 (juejin.cn)

面试官:怎么理解回流跟重绘?什么场景下会触发? | web前端面试 - 面试官系列 (vue3js.cn)

浏览器渲染过程

渲染页面:浏览器的工作原理 - Web 性能 | MDN (mozilla.org)

image-20220208145056464

  1. 解析HTML,形成DOM树,当遇到非阻塞资源时,如图片则会继续解析,当遇到css文件时,也会继续解析。当时遇到了js文件(特别是没有defer和async)的阻塞渲染并停止HTML的解析。
  2. 构建CSSOM树。浏览器将CSS规则转换为可以理解和使用的样式映射。浏览器遍历CSS中的每个规则集,根据CSS选择器创建具有父、子和兄弟关系的节点树。
  3. 第三步是将DOM和CSSOM组合成一个Render树,计算样式树或渲染树从DOM树的根开始构建,遍历每个可见节点。像和它的子节点以及任何具有display: none样式的结点,例如script { display: none; }(在user agent stylesheets可以看到这个样式)这些标签将不会显示,也就是它们不会出现在Render树上。具有visibility: hidden的节点会出现在Render树上,因为它们会占用空间。由于我们没有给出任何指令来覆盖用户代理默认值,因此上面代码示例中的script节点将不会包含在Render树中。
  4. 第四步是在渲染树上运行布局以计算每个节点的几何体。(回流\重排)。在此阶段,考虑到视区大小,浏览器将确定屏幕上所有不同框的尺寸。以视区的大小为基础,布局通常从body开始,用每个元素的框模型属性排列所有body的子孙元素的尺寸,为不知道其尺寸的替换元素(例如图像)提供占位符空间。
  5. 最后一步是将各个节点绘制到屏幕上。

回流一定会触发重绘,重绘不一定会触发回流。

生成渲染树

image-20220208150955390

  1. 从DOM树的根开始构建,遍历每个可见节点
  2. 对于每一个可见节点,找对应的CSSOM规则。
  3. 根据每一个可见节点和它们对应的CSSOM规则,结合形成Render Tree.

不可见节点

  1. Head标签下的所以子节点(meta、link)。
  2. script。
  3. display : none 的元素
  4. 利用visibility和opacity隐藏的节点,还是会显示在渲染树上的。

回流

以视区的大小为基础,布局通常从body开始,用每个元素的框模型属性排列所有body的子孙元素的尺寸,为不知道其尺寸的替换元素(例如图像)提供占位符空间。

总的来说就是计算它们在设备视口(viewport)内的确切位置和大小(也就是几何属性和位置),这个计算的阶段就是回流。

重绘

我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。也就是在屏幕上绘制图形,但是如背景颜色发生改变,那么会引起重绘,但是不会引发回流。

触发回流重绘的操作

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
  • 页面一开始渲染的时候(这肯定避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

浏览器的优化机制

image-20220208161045011

减少回流和重绘的方法

  1. 把多个操作DOM操作合并在一起—使用csstext或者class

    image-20220208161212390

  2. 使得节点脱离文档流(也就是不可见的节点),操作,回到文档流。

    1. 使用display: none
  3. 必须触发布局事件

    也就是offset这些。若多次使用到同一个offset,那么可以先把它的值保存起来再使用。

  4. 对于复杂的动画可以使用绝对定位使其脱离文档流。对于复杂动画效果,由于会经常的引起回流重绘,因此,我们可以使用绝对定位,让它脱离文档流。否则会引起父元素以及后续元素频繁的回流。

Logo

前往低代码交流专区

更多推荐