回流重绘

一、浏览器的渲染过程

在这里插入图片描述

  浏览器在渲染的时候,会解析html生成DOM树,解析css生成CSSOM树,然后两个树合并生成渲染树
生成渲染树浏览器完成了那些工作?

  • 从DOM数的根节点开始遍历可见的节点
  • 对于可见的节点,找到CSSOM树中对应的规则,并应用它们
  • 根据每个节点和它对应的样式,生成渲染树

注意:不可见节点包括script、meta、link等,以及通过css进行隐藏的节点,比如display:none。但visibility和opacity隐藏的节点,还是会显示在渲染树上的。

二、回流

  构造完渲染树后,计算它们在设备视口内的确切位置和大小,这个计算阶段就是回流。
下面有个实例:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>回流</title>
  </head>
  <body>
     <div style="width: 50%">
       <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

在这里插入图片描述

第一个div节点将显示尺寸设置为视口宽度的50%,第二个div节点将显示尺寸显示为第一个div宽度的50%,而在回流这个阶段,我们就需要根据视口具体的宽度,将其转换为具体的像素值。

三、重绘

  最终,我们通过构造渲染树和回流阶段,我们知道了那些节点是可见的,以及可见节点的样式和具体的几何信息,那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。(说人话就是将每个节点上对应的样式渲染出来)

四、何时发生回流重绘

  回流这一阶段是计算节点位置和几何信息,那么页面上的布局发生改变时就会发生回流,比如以下几种状况:

  • 添加或删除可见的DOM元素
  • 元素的位置发生改变
  • 元素的尺寸发生变化(外边距,边框、内边距、宽高等)
  • 元素内容发生变化
  • 页面打开渲染时
  • 浏览器的窗口尺寸变化

注意:回流一定会触发重绘,但重绘不一定会触发回流

根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排,比如滚动条出现的时候或者修改了根节点。

五、浏览器优化机制

  现在的浏览器会通过队列化修改并批量执行来优化重排过程,浏览器会将修改操作放到队列里,直到过了一段时间或者操作达到了阈值,才清空队列。当你获取布局信息的操作的时候,会强制更新队列。比如你访问了以下属性或方法:

  1. offsetTop、offsetLeft、offsetWidth、offsetHeight
  2. scrollTop、scrollLeft、scrollWidth、scrollHeight
  3. clientTop、clientLeft、clientWidth、clientHeight
  4. getComputedStyel()
  5. getBoundingClientRect()

以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回正确的值。因此,我们在修改样式的时候,最好避免使用上面列出的属性,他们都会刷新渲染队列。如果要使用它们,最好将值缓存起来。

六、如何减少回流和重绘

最小化重绘和重排

     合并对DOM的操作,将多次对DOM的操作合并为一次,减少发生次数。

批量修改DOM

当我们需要对DOM进行一系列的修改时,可以通过以下步骤减少回流重绘次数:

  1. 让元素脱离文档流
  2. 对其进行多次修改
  3. 将元素带回到文档中

有三种方式可以让DOM脱离文档流:

  1. 隐藏元素,应用修改,重新显示
  2. 使用文档碎片(documentFragment)在当前DOM之外构建一个子树,再把它拷贝回文档中。
  3. 将原始元素拷贝到一个脱离文档的节点中,修改节点后,再替换原始的元素。

避免触发同步布局事件

function initP () {
  for (let i = 0; i < 10; i++) {
    p[i].style.width = box.offsetWidth + 'px' 
  }
}

  上面这段代码在每次循环的时候,都会读取box的offsetWidth属性值,然后更新p标签的width属性。导致每一次循环的时候,浏览器都必须使上一次循环中的样式更新操作生效,才能响应本次循环的样式读取操作。
我们可以这样优化代码:

function initP () {
  const boxWidth = box.offsetWidth
  for (let i = 0; i < 10; i++) {
    p[i].style.width = boxWidth + 'px' 
  }
}

对于复杂动画效果,使用绝对定位让其脱离文档流

CSS3硬件加速(GPU加速)
  比起如何减少回流重绘,我们更期望的是,不要回流重绘。这个时候,CSS3硬件加速就闪亮登场啦。
  使用CSS3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘。但是对于动画的起他属性,比如background-color这些,还是会引起回流重绘的。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值