Skip to content

回流和重绘 #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Twlig opened this issue Mar 21, 2022 · 0 comments
Open

回流和重绘 #59

Twlig opened this issue Mar 21, 2022 · 0 comments
Labels

Comments

@Twlig
Copy link
Owner

Twlig commented Mar 21, 2022

回流和重绘

  • 回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
  • 重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制

浏览器解析渲染机制

image

  • 解析HTML,生成DOM树,解析CSS,生成CSSOM树
  • 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
  • Layout(布局):根据生成的渲染树,计算每个渲染对象的几何属性,浏览器会遍历渲染树,确定每个对象显示在页面上的什么位置。
  • Painting(绘制):根据渲染树以及布局得到的几何信息,浏览器计算出它们在屏幕上占据的像素数。
  • Display:将像素发送给GPU,展示在页面上
    当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来

当我们对 DOM的修改导致了样式的变化(color或background-color),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了重绘。

触发

回流

回流主要计算节点的位置和几何信息,那么当页面布局和几何信息发生变化时,就需要回流。

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

还有一些容易被忽略的操作:获取一些特定属性的值

offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight

这些属性有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流。

重绘

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

  • 颜色修改
  • 文本方向修改
  • 阴影修改

优化

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop等方法都会返回最新的数据。因此浏览器不得不清空队列,触发回流重绘来返回正确的值。

避免回流

  • 如果想设定元素的样式,通过改变元素的 class 类名 (尽可能在 DOM 树的最里层):class替代style
  • 避免设置多项内联样式
  • 应用元素的动画,使用 position 属性的 fixed 值或 absolute 值(如前文示例所提)
  • 避免使用 table 布局,table 中每个元素的大小以及内容的改动,都会导致整个 table 的重新计算
  • 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响
  • 使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘
  • 避免使用 CSS 的 JavaScript 表达式
  • 使用scroll时进行防抖和节流处理

具体操作:

  • 离线操作
    设置元素属性display:none,将其从页面上去掉,然后再进行后续操作,这些后续操作将不会触发回流和重绘。
const container = document.getElementById('container')
container.style.width = '100px'
container.style.height = '200px'
container.style.border = '10px solid red'
container.style.color = 'red'

离线操作后:

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'

如何根据浏览器渲染机制加快首屏速度

  • 优化文件大小:HTML和CSS的加载和解析都会阻塞渲染树的生成,从而影响首屏展示速度,因此我们可以通过优化文件大小、减少CSS文件层级的方法来加快首屏速度。
  • 避免资源下载阻塞文档解析:浏览器解析到<script>标签时,会阻塞文档解析,直到脚本执行完成,因此我们通常把<script>标签放在底部,或者加上defer、async来进行异步下载。

原文链接:回流和重绘

@Twlig Twlig added the CSS label Mar 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant