跳到主要内容

重绘和重排(回流)

重绘不一定导致重排,但重排一定会导致重绘 重排(Reflow) && 重绘(Redraw)会付出高昂的性能代价

重排(Reflow): 重排是指浏览器需要重新计算元素的位置和大小,然后重新绘制整个页面的过程。这可能由于以下原因触发:

  • 添加、删除或改变 DOM 元素。
  • 改变窗口大小。
  • 修改元素的样式,如改变宽度、高度、边距、填充、边框等。
  • 获取某些元素的布局信息(如宽度、高度、位置)。

重排是非常昂贵的操作,因为它会导致整个页面重新布局和绘制,对性能产生负面影响。

重绘(Repaint): 重绘是指在不影响页面布局的情况下,改变元素的外观样式而引起的页面重新绘制。这包括修改元素的颜色、背景、字体等属性,而不会导致元素的位置和大小发生变化。重绘比重排开销小,但仍然会消耗一定的性能资源。

浏览器的工作流程

解析HTML和构建DOM树:浏览器首先解析HTML,构建DOM(文档对象模型)树。DOM树表示页面的结构,每个元素都是树中的一个节点。

解析CSS和构建CSSOM树:接下来,浏览器解析CSS样式表,并构建CSSOM(CSS对象模型)树。CSSOM树表示页面的样式信息,每个CSS规则都是树中的一个节点。

合并DOM树和CSSOM树,构建渲染树:浏览器将DOM树和CSSOM树合并成一个渲染树(Render Tree)。渲染树只包含需要渲染的可见元素,不包括不可见的元素(例如 display: none 的元素)。

布局(回流):一旦有了渲染树,浏览器就需要计算每个元素在屏幕上的确切位置和大小,这个过程叫做布局或回流。它会确定元素的位置、尺寸和相互关系。

绘制(重绘):一旦布局完成,浏览器就可以进行绘制或重绘操作。这时候,浏览器知道每个元素在屏幕上的准确位置和外观,可以开始将它们绘制到屏幕上。

合成与显示:最后,浏览器将渲染树的内容进行合成,并显示在屏幕上,呈现给用户。

造成重绘

重绘(Repaint)是在不改变元素布局的情况下,修改元素外观样式而引发的页面重新绘制。以下是一些可能触发重绘的动作:

  1. 修改元素的样式属性: 修改元素的颜色、背景、字体、文本颜色等样式属性。

  2. 添加、删除或更改类名: 当您通过JavaScript修改元素的类名时,可能会导致重绘,特别是在修改了影响样式的类名时。

  3. 修改伪类状态: 例如,当使用 :hover:active:focus 伪类选择器时,鼠标悬停在元素上或元素获得焦点时,可能会触发重绘。

  4. 改变文本内容: 修改元素的文本内容(不是文本样式)也可能引发重绘。

  5. 改变背景图像: 当您修改元素的背景图像或相关属性时,会触发重绘。

  6. 添加或删除伪元素(::before 和 ::after): 添加或删除伪元素可能会导致重绘,因为它们可以包含样式属性。

  7. 使用 CSS 动画和过渡: 使用 CSS 动画和过渡会导致元素的重绘,但通常不会引发重排。

  8. 滚动页面: 滚动页面时,页面上的元素可能会因显示或隐藏而触发重绘。

  9. 修改字体属性: 修改元素的字体属性(如字体大小、字体样式)可能导致重绘。

需要注意的是,重绘虽然比重排开销小,但仍然会消耗性能资源。因此,为了提高页面性能,应尽量减少不必要的重绘操作,特别是在需要频繁更新元素样式的情况下。优化页面的渲染性能是前端开发中重要的任务之一。

造成重排

重排(Reflow)是浏览器中一种昂贵的操作,它会重新计算元素的位置和大小,然后更新页面的布局。以下是一些可能触发重排的动作:

  1. 添加、删除或改变 DOM 元素结构: 任何更改 DOM 结构的操作都可能引发重排,包括添加、删除、移动、更改元素的属性等。

  2. 修改元素的布局属性: 修改元素的样式属性,如宽度、高度、内边距、外边距、边框等,通常会引发重排。

  3. 获取元素的布局信息: 使用 JavaScript 获取元素的布局信息,如 offsetWidthoffsetHeightclientWidthclientHeight 等,会强制浏览器重新计算布局。

  4. 改变窗口大小: 当用户改变浏览器窗口大小时,页面的布局会发生变化,因此会触发重排。

  5. 滚动页面: 如果用户滚动页面,页面上的元素可能会因显示或隐藏而触发重排。

  6. 改变字体大小: 修改字体大小可能会影响整个文档的布局,因此会触发重排。

  7. 激活 CSS 伪类: 例如,使用 :hover:active:focus 伪类选择器会改变元素的状态,可能触发重排。

  8. 更改表单元素: 用户与表单元素交互,如输入文本、选择选项、勾选复选框等,可能会导致页面重新布局,从而触发重排。

  9. 调整浏览器的默认字体: 一些浏览器在首次渲染页面时需要获取默认字体信息,如果修改了默认字体,可能会导致重排。

  10. 动画操作: 使用 JavaScript 或 CSS 动画会频繁地修改元素的样式,这可能触发多次重排。

需要注意的是,重排是非常昂贵的操作,它会导致整个页面重新布局和绘制,对性能产生负面影响。因此,在开发中应该尽量避免不必要的重排操作,合理优化页面结构和样式,以提高页面的性能。

如何避免重绘和重排提高性能

要避免重绘和重排以提高性能,可以采取以下一些最佳实践:

  1. 使用 CSS3 动画和过渡: CSS3 提供了 transformopacity 属性,它们通常会触发重绘而不会引发重排。如果需要创建动画效果,请尽量使用 CSS3 动画和过渡,而不是使用 JavaScript 操作 DOM。

  2. 使用离屏渲染: 对于复杂的动画或渲染效果,可以考虑使用离屏渲染技术。这将元素绘制到一个不可见的缓冲区中,然后再将结果绘制到页面上。这可以减少页面的重绘开销,但需要小心使用,因为它可能会增加内存占用。

  3. 使用硬件加速: 某些属性(如 transformopacity)可以触发浏览器的硬件加速,从而减少重绘的成本。确保您的动画或效果使用了硬件加速。

  4. 最小化样式变化: 修改样式属性时,尽量避免改变元素的布局。这包括尽量不修改宽度、高度、边距、填充等属性,因为这些变化可能导致重排。如果需要改变布局,最好一次性应用所有变化,而不是逐个修改。

  5. 使用 will-change 属性: will-change 属性可以告诉浏览器哪些属性将会发生变化,从而优化渲染过程。例如,可以使用 will-change: transform; 来提示浏览器元素将进行变换。

  6. 避免频繁查询布局信息: 尽量不要使用会触发布局的属性(如 offsetWidthoffsetHeight)来获取元素的布局信息。如果需要多次查询,最好将结果缓存起来,以减少性能开销。

  7. 使用缓存: 对于需要多次计算的值,可以将结果缓存起来,避免重复计算。这在计算复杂布局时特别有用。

  8. 使用 requestAnimationFrame 如果您需要执行动画效果,可以使用 requestAnimationFrame 来优化动画的性能。它会在下一帧绘制之前调用,有助于避免不必要的重绘。

通过遵循这些最佳实践,可以减少页面的重绘和重排次数,从而提高页面的性能和响应速度。选择合适的方法取决于您的具体应用场景和需求。