前端性能优化-重绘与回流

发布时间:2024年01月17日

在开发中,页面的性能优化很重要。性能优化的核心目标是提升用户体验,减少页面加载时间,提高页面的响应速度。

而在前端性能优化的过程中,优化重绘(repaints)与回流(reflow)是非常关键的。本文将介绍重绘与回流、以及如何减少它们对性能的影响。请注意:回流一定引起重绘,重绘不一定引起回流

浏览器渲染机制

在这里插入图片描述

我们先来对浏览器的渲染机制有个初步的了解。浏览器的解析渲染机制可以分为以下几个步骤:

  1. 解析(Parsing):
  • 浏览器开始解析接收到的HTML文档,将其转换为DOM(Document Object Model)树。
  • 如果文档中含有CSS,浏览器会同时解析CSS并构建CSSOM(CSS Object Model)树。
  • 如果文档中含有JavaScript,浏览器会暂停HTML的解析,优先执行JavaScript代码(这是因为JavaScript可能会修改DOM结构)。
  1. 构建渲染树(Render Tree Construction):
  • 浏览器将DOM树和CSSOM树结合,构建渲染树。渲染树只包含需要显示的节点和这些节点的样式信息。
  • 不可见的节点(如标有display: none;的节点)不会被包含在渲染树中。
  1. 布局(Layout):
  • 浏览器计算渲染树中每个节点的确切位置和大小,这个过程称为布局或重排(reflow)。
  • 布局是一个递归过程,它从根元素开始,递归遍历整个渲染树。
  1. 绘制(Painting):
  • 浏览器开始将渲染树中的每个节点绘制到屏幕上,这个过程称为绘制或重绘(repaint)。
  • 绘制包括将文本、颜色、图像、边框、阴影等绘制到屏幕上。
  1. 合成(Compositing):
  • 现代浏览器通常会在多个层上分别进行绘制,然后将这些层合成在一起,显示到屏幕上。这个过程称为合成。
  • 合成层可以独立于其他层进行变换和动画,这可以提高性能,因为它可以避免不必要的重绘和回流。

重绘(Repaints)

重绘是指当页面中元素样式的改变不影响布局时,浏览器会将新样式应用到元素上,这个过程称为重绘。 例如,改变一个元素的背景色、文字颜色等样式时,浏览器只会重新绘制这个元素,而不会影响到其他元素的布局。

重绘是一个成本相对较低的操作,因为它只涉及到单个元素的样式更新,不需要重新计算整个页面的布局。但是,如果重绘操作频繁发生,尤其是对于大量的元素来说,仍然会消耗大量的CPU资源和时间,导致页面响应速度变慢。

下面是一个简单的HTML和CSS代码,通过JavaScript改变元素的背景色,这将导致重绘。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Repaint Example</title>
<style>
  .box {
    width: 100px;
    height: 100px;
    background-color: blue;
  }
</style>
</head>
<body>
<div class="box" id="box"></div>
<script>
  // 改变元素的背景色,这将导致重绘
  function changeColor() {
    document.getElementById('box').style.backgroundColor = 'red';
  }
  // 每秒改变一次颜色
  setInterval(changeColor, 1000);
</script>
</body>
</html>

由于 setInterval 这个操作只改变了盒子的颜色,而没有改变其布局,所以浏览器将执行重绘操作。

回流(Reflow)

回流是指当页面中元素的尺寸、位置、布局等发生变化时,浏览器需要重新计算整个页面的布局,这个过程称为回流。

回流是一个成本非常高的操作,因为它涉及到整个页面的重新布局,需要重新计算所有元素的尺寸和位置。

引起回流的原因有很多,比如改变元素的宽度、高度、字体大小、内外边距、边框宽度等样式,或者是添加或删除元素,都会导致浏览器重新计算布局。回流的发生会导致页面响应速度变慢,尤其是在移动设备和低性能设备上更为明显。

我们看下下面这个例子,通过JavaScript改变元素的宽度和高度:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reflow Example</title>
<style>
  .box {
    width: 100px;
    height: 100px;
    background-color: blue;
  }
</style>
</head>
<body>
<div class="box" id="box"></div>
<script>
  // 改变元素的宽度和高度,这将导致回流
  function changeSize() {
    document.getElementById('box').style.width = '200px';
    document.getElementById('box').style.height = '200px';
  }
  // 每秒改变一次大小
  setInterval(changeSize, 1000);
</script>
</body>
</html>

通过setInterval每秒调用changeSize函数,将盒子的宽度和高度都改为200px。由于这个操作改变了盒子的尺寸,浏览器需要重新计算布局,这将导致回流。

如何减少重绘与回流

为了提高页面性能,我们需要尽量减少重绘与回流的发生。以下是一些减少重绘与回流的方法:

  • 样式集中改变:将多次样式改变合并为一次,例如使用CSS类名切换或者使用CSS3的过渡和动画效果。
  • 避免不必要的DOM操作:尽量减少DOM的读写操作,可以使用文档片段(DocumentFragment)来批量更新DOM。
  • 使用虚拟DOM:使用前端框架(如React、Vue等)的虚拟DOM特性,可以在内存中先进行DOM操作,然后再一次性应用到真实DOM上,减少重绘与回流。
  • 避免使用复杂的CSS选择器:复杂的CSS选择器会增加浏览器的解析和匹配时间,导致重绘与回流。
  • 避免在循环中访问布局属性:在JavaScript循环中避免访问会触发回流的布局属性,可以将这些属性缓存起来。
  • 使用requestAnimationFrame:对于连续的动画效果,可以使用requestAnimationFrame来控制动画的更新,减少重绘与回流。
  • 使用CSS的will-change属性:提前告诉浏览器哪些元素将会发生变化,浏览器可以提前进行优化。
文章来源:https://blog.csdn.net/qq_37834631/article/details/135654652
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。