再也不怕面试官问重排和重绘了

92 阅读4分钟

HTML的渲染流程

  1. 解析HTML,生成DOM树(Document Object Model Tree)
  2. 解析css,构建CSSOM(CSS Object Model Tree)
  3. 合并DOM和CSSOM构建渲染树(Render Tree)
  4. 布局,计算每个元素在屏幕上的位置和大小(这个阶段也叫回流/重排)
  5. 绘制:将渲染树中的每个节点转换为屏幕上的实际像素(重绘)
  6. 合成:将多个层合并为最终的视觉输出。

重排(回流)

  • 定义: 当渲染树中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建时,就会发生重排。这意味着浏览器需要重新计算元素的几何属性(位置和大小),并重新构建渲染树,然后将渲染树绘制到屏幕上。重排是一个代价高昂的操作,因为它会影响到页面的布局,可能导致一系列元素的位置和尺寸发生变化。

  • 触发重排的操作

    • 改变窗口大小:当浏览器窗口的大小发生改变时,页面中元素的布局可能需要重新计算,以适应新的窗口尺寸,这会触发重排。例如,用户拖动浏览器窗口的边框来调整窗口的宽度或高度。
    • 改变字体大小:字体大小的改变会影响文本占据的空间大小,进而可能影响到周围元素的布局,从而触发重排。比如,通过 CSS font - size 属性改变字体大小。
    • 添加或删除可见的 DOM 元素:添加新的 DOM 元素或者删除已有的 DOM 元素,会改变渲染树的结构,导致浏览器重新计算布局,触发重排。例如,使用 JavaScript 的 document.createElement() 创建新元素并添加到 DOM 树中,或者使用 removeChild() 方法删除元素。
    • 改变元素的位置:改变元素的 topleftrightbottom 等定位属性,或者修改 display 属性(例如从 none 改为 block 或反之),会使元素的位置或布局发生变化,从而触发重排。
    • 改变元素的尺寸:修改元素的 widthheightpaddingmargin 等属性,会改变元素的大小和占据的空间,导致重排。例如,通过 JavaScript 动态修改一个元素的宽度。
    • 内容变化:当元素的文本内容发生变化,导致其宽度或高度改变时,也会触发重排。比如,一个 <div> 元素中的文本增加或减少,可能会使该 <div> 的尺寸改变,进而影响周围元素的布局。

重绘

  • 定义:当元素的外观发生改变,但布局没有改变时,就会发生重绘。例如,改变元素的颜色、背景色、边框样式等,这些操作只影响元素的绘制,而不会影响其在文档流中的位置和布局。重绘的代价相对重排较小,但仍然会消耗一定的性能。

  • 触发重绘的操作

    • 改变元素的颜色:通过 CSS color 属性改变文本颜色,或者使用 background - color 属性改变元素的背景颜色,会触发重绘。因为这些操作只改变了元素的外观,而不影响其布局。
    • 改变元素的边框样式:修改 border - style(如从 solid 改为 dashed)、border - color 或 border - width 等边框相关属性,会导致元素的边框外观改变,从而触发重绘。
    • 改变元素的透明度:使用 opacity 属性改变元素的透明度,元素的可见性外观发生变化,但布局不受影响,会触发重绘。例如,将一个元素的 opacity 从 1 改为 0.5,使其变得半透明。
    • 改变元素的盒阴影:修改 box - shadow 属性,为元素添加、移除或改变盒阴影的样式,会使元素的外观发生变化,触发重绘。

扩展点

  • 重排一定会触发重绘,重绘不会触发重排。
  • 为了优化性能,应该尽量减少重排和重绘的发生。例如修改样式时一次性修改而不是一次修改一种样式。获取元素属性时也是同样的道理。