基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

浏览器的重绘 (Repaint) 和回流 (Reflow/Layout)的区别?

知识点图片

浏览器的 重绘 (Repaint)回流 (Reflow,也称重排/Layout) 是前端性能优化中非常核心的概念。理解它们的区别有助于写出性能更好的页面。

简单的一句话总结:回流一定会触发重绘,但重绘不一定会触发回流。


1. 概念定义

为了理解这两个概念,首先需要知道浏览器渲染页面的简要流程:

  1. 解析 HTML 生成 DOM 树。
  2. 解析 CSS 生成 CSSOM 树。
  3. 将 DOM 和 CSSOM 合并生成 渲染树 (Render Tree)
  4. 回流 (Layout/Reflow):根据渲染树,计算每个节点在屏幕上的几何信息(位置、大小)。
  5. 重绘 (Painting):根据计算好的几何信息,将节点的像素(颜色、背景等)绘制到屏幕上。
  6. 合成 (Composite):将多个层合成最终图像。

回流 (Reflow / Layout)

当渲染树中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

  • 核心: 涉及几何信息(位置、大小)的改变。
  • 比喻: 就像你在房间里重新摆放家具,你移动了沙发,可能连带茶几也要移动,整个房间的布局都变了。

重绘 (Repaint)

当元素样式的改变不影响它在文档流中的位置(如颜色、背景色、边框颜色等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

  • 核心: 涉及外观(颜色、风格)的改变,不影响布局。
  • 比喻: 就像给沙发换了个红色的套子,沙发的位置和大小没变,房间布局也没变,只是样子变了。

2. 详细区别对比

特性 回流 (Reflow) 重绘 (Repaint)
触发条件 元素的几何属性(宽、高、位置)或结构发生变化。 元素的外观属性(颜色、背景)发生变化,但几何属性未变。
性能消耗 非常高。可能导致整个页面重新布局。 较低。只改变像素颜色,不涉及几何计算。
相互关系 回流必将引起重绘 重绘不一定引起回流
影响范围 全局(整个页面)或 局部(某个 DOM 分支)。 仅受影响的元素本身。

3. 常见触发场景

触发回流 (Reflow) 的操作(代价大)

只要涉及“动了位置”或“变了大小”,就会回流:

  1. 页面首次渲染(无法避免)。
  2. 浏览器窗口大小发生改变(Resize)。
  3. 元素尺寸或位置发生改变width, height, padding, margin, left, top, border)。
  4. 元素内容变化(文字数量变化、图片大小变化、输入框输入文字)。
  5. 元素字体大小变化font-size)。
  6. 添加或者删除可见的 DOM 元素
  7. 激活 CSS 伪类(如 :hover)。
  8. 查询某些属性或调用某些方法强制同步布局):
    • offsetWidth, offsetHeight, clientWidth, clientHeight, scrollTop, scrollHeight 等。
    • getComputedStyle()
    • 原因:浏览器为了返回最新的值,必须强制立即执行一次回流。

触发重绘 (Repaint) 的操作(代价小)

只涉及“样子变了”:

  1. color
  2. background-color / background-image
  3. visibility (注意:visibility: hidden 只是看不见,位置还在,所以是重绘;而 display: none 彻底消失,会触发回流)
  4. outline
  5. box-shadow

4. 性能优化策略

既然回流的代价很高,我们需要尽量避免或减少回流。

  1. 避免频繁操作 DOM

    • 使用 DocumentFragment 创建一个文档碎片,在它上面批量操作 DOM,最后一次性添加到文档中。
    • 或者先 display: none 隐藏元素(触发一次回流),进行多次修改,再 display: block 显示(再触发一次回流)。
  2. 避免频繁读取布局信息(读写分离)

    • 错误写法(导致多次回流):
      javascript
      // 读一次,写一次,浏览器被迫不断重排
      div.style.left = div.offsetLeft + 1 + 'px';
      div.style.top = div.offsetTop + 1 + 'px';
    • 正确写法(缓存布局信息):
      javascript
      // 先读完
      const curLeft = div.offsetLeft;
      const curTop = div.offsetTop;
      // 再统一写
      div.style.left = curLeft + 1 + 'px';
      div.style.top = curTop + 1 + 'px';
  3. 使用 CSS 类合并样式修改

    • 不要一条条修改 style 属性,而是定义一个 CSS class,一次性切换类名。
  4. 使用 transformopacity 实现动画

    • 这是现代前端优化的关键点。
    • 修改 transform (位移、缩放) 和 opacity 属性,在某些浏览器中会触发硬件加速 (GPU),既不会触发回流,甚至可能不会触发重绘(直接在合成层处理),性能极高。
  5. 将复杂的动画元素脱离文档流

    • 给动画元素设置 position: absolutefixed。这样它在回流时,只会影响它自己,不会推挤周围的元素,减少回流的影响范围。

总结

  • 回流是布局计算,重绘是像素绘制。
  • 回流成本远高于重绘
  • 优化目标:减少回流次数,缩小回流范围
00:00
00:00