如何优化重排和重绘??

133 阅读7分钟
Screenshot_20230628_094744_com.nowcoder.app.flori.jpg

display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发生位置变化。

面试题: 怎么理解回流跟重绘?什么场景下会触发

image.png

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

重排(回流)

重排(Reflow),也称为布局(Layout),是指浏览器根据CSS样式和文档结构计算元素的几何属性(位置和尺寸),然后确定它们在页面中的精确位置。当页面的布局发生变化时,浏览器需要重新计算和确定元素的位置,这个过程就是重排。
例如,当添加、删除或修改元素的尺寸、位置或显示状态时,浏览器需要重新计算并重新布局页面

定义: 布局引擎会根据各种样式计算每个盒子在页面上的大小与位置,这个计算的过程叫做回流

触发回流的情况:

常见的触发重排的操作包括改变元素的尺寸、位置、字体大小、文本内容、添加或删除元素等

  1. 页面一开始渲染的时候
  2. 添加或删除可见的DOM元素
  3. 元素的位置发生变化
  4. 元素的尺寸发生变化(包括margin,padding,边框大小,width,height等)
  5. 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
  6. 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

重绘

重绘(Repaint),也称为渲染(Render),是指根据元素的样式属性将像素绘制到屏幕上。
当元素的样式(如颜色、背景、边框等)发生变化时,浏览器需要重新绘制元素,但不会改变其几何属性
重绘比重排的代价要小,因为它只涉及像素的重新绘制,而不需要重新计算元素的布局。

定义:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制

通常情况下,重排会导致重绘,因为重排会改变元素的几何属性,进而触发浏览器重新绘制这些元素。然而,仅仅触发重绘而不涉及重排的操作,如 改变颜色、背景图像 等,对性能的影响相对较小。

通常只触发重绘不触发重排

  1. 改变元素的背景颜色、文本颜色或字体样式:修改这些样式属性通常只会引起重绘而不会影响元素的布局。
  2. 修改元素的阴影或渐变效果:改变元素的阴影或渐变效果通常只会引起重绘而不会引起重排。
  3. 改变元素的可见性或透明度:修改元素的可见性或透明度通常只会触发重绘而不会引起重排。
  4. 修改元素的 transformopacity 属性:使用 CSS3 的 transform 属性进行旋转、缩放或平移,或者使用 opacity 属性改变元素的透明度,通常只会触发重绘。
  5. 修改元素的 box-shadow 属性:改变元素的阴影效果通常只会触发重绘而不会引起重排。
  6. 修改元素的 outline 属性:改变元素的轮廓样式通常只会引起重绘而不会引起重排。

减少重排和重绘

1. 使用CSS3硬件加速( will-change: transform ):

使用CSS3的transform和opacity属性可以开启硬件加速,这样浏览器会将元素的渲染交给GPU处理,减少CPU的工作量。使用css3硬件加速,可以让transform、opacity、filters这些动画不会引起回流重绘。但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能

  • css3硬件加速的坑

    如果你为太多元素使用css3硬件加速,会导致内存占用较大,会有性能问题。在GPU渲染字体会导致抗锯齿无效。这是因为GPU和CPU的算法不同。因此如果你不在动画结束的时候关闭硬件加速,会产生字体模糊。

    抗锯齿是一种图形渲染技术,旨在减少图像边缘处的锯齿状锯齿或颗粒状的边缘
    抗锯齿技术的应用可以改善图像和图形的视觉质量,使其更加平滑和真实

  • 具体使用

  • 将一个元素单独一个图层

    #target {
      will-change: transform;
    }
    
    1. transform
      1. transform结合图层使用不会触发重绘,也不会触发重排
      2. transform结合定位position:relative只触发重绘
      3. transform单独使用,既重绘也重排。
    2. opacity 和 visibility
      1. 使用visibility不触发重排,但是依然重绘。
      2. 使用opacity即触发重绘,又触发重排。(GPU底层设计如此)
      3. opacity配合图层使用,不会触发重绘也不触发重排

2. 避免频繁访问样式属性

避免在JavaScript中频繁读取样式属性,因为每次读取都会导致浏览器重新计算样式,触发重排。最好将需要多次使用的样式属性缓存起来。(读写分离)

在读取元素的几何属性(如宽度、高度、偏移量等)之前,确保浏览器已经完成重排,否则会强制触发重排操作。

字节前端提前批面试题:触发了几次回流几次重绘

3. 通过class统一操作元素样式

尽量将多次重排的操作合并为一次,可以通过修改元素的样式类名,然后一次性应用样式,减少重排次数。

4. 使用文档片段 DocumentFragment

当需要频繁添加多个DOM元素到文档中时,可以使用文档片段(DocumentFragment)进行操作,最后一次性将片段添加到文档中,减少重排和重绘次数。

浏览器的渲染机制

image.png

  1. 构建 DOM 树:浏览器解析 HTML 文档,并将其转换为 DOM(文档对象模型)树的结构。

DOM 树表示文档的逻辑结构,其中每个 HTML 元素都表示为一个节点,并形成父子关系。

  1. 构建 CSSOM 树:浏览器解析 CSS 样式表,并将其转换为 CSSOM(CSS 对象模型)树的结构。CSSOM 树表示文档的样式信息,其中每个 CSS 规则都表示为一个节点,并与 DOM 树相对应。
  2. 合并 DOM 树和 CSSOM 树形成 Render Tree:浏览器将 DOM 树和 CSSOM 树合并成为渲染树(也称为呈现树或布局树),渲染树只包括需要显示的元素及其样式信息。渲染树的构建过程中,一些元素可能会被隐藏、剪切或不可见。
  3. 执行重排( reflow):浏览器根据渲染树的信息计算每个元素在屏幕上的几何位置和尺寸,即布局过程。这个过程也被称为布局(Layout)或排版,它确定了元素在屏幕上的精确位置。
  4. 执行重绘(repaint):浏览器根据布局的结果,将渲染树中的元素转换为屏幕上的实际像素,即绘制过程。这个过程也被称为绘制(Painting),它将元素的可见样式应用于实际像素。
  5. 合成图层(Compositing):如果页面中有多个图层,浏览器会将这些图层合成为最终的图像。合成图层可以通过硬件加速,以提高性能和动画效果的流畅度。
  6. 显示图像:最后,浏览器将合成后的图像发送给屏幕,显示在用户的可视区域
image.png
  1. 渲染进程将HTML内容转换为浏览器能够读懂的DOM树结构。
  2. 渲染引擎将CSS样式表转化为浏览器能够理解的css树,计算出DOM节点的样式。
  3. DOM树+css树创建布局树,并计算元素的布局信息。
  4. 对布局树进行分层,并生成图层树
  5. 对每个图层生成绘制列表,并将其提交给合成线程。
  6. 对每个图层进行单独的绘制
  7. 合并图层。

渲染树

image.png