缩小样式计算的范围并降低其复杂性

视觉变化通常是通过 JavaScript 触发的。有时是直接通过样式操作,有时是通过会产生视觉变化的计算(例如搜索数据或将其排序)来进行这些更改。时机不当或长时间运行的 JavaScript 可能是导致性能问题的常见原因,您应当设法尽可能减少其影响。

样式计算

通过添加和移除元素、更改属性、类或播放动画来更改 DOM 会导致浏览器重新计算元素样式,在很多情况下还会重新计算网页的部分或全部布局。此过程称为“样式计算”。

浏览器会先创建一组匹配选择器,以确定要为指定元素应用哪些类、伪选择器和 ID,然后再开始计算样式。然后,它会处理匹配选择器中的样式规则,并计算出此元素的最终样式。

样式重新计算在互动延迟时间中的作用

Interaction to Next Paint (INP) 是一项以用户为中心的运行时性能指标,用于评估网页对用户输入的总体响应情况。该指标用于衡量从用户与网页互动到浏览器绘制下一个帧(显示界面相应的视觉更新)之间的互动延迟时间。

互动的一个重要组成部分是绘制下一帧所需的时间。为了呈现下一帧而执行的渲染工作由许多部分组成,包括在布局、绘制和合成工作之前进行的页面样式计算。本指南重点介绍样式计算开销,但缩短互动总渲染时长的任何部分也会缩短其总延迟时间。

降低选择器的复杂性

简化 CSS 选择器有助于加快网页的样式计算速度。 最简单的选择器只需使用类名称即可在 CSS 中引用元素:

.title {
  /* styles */
}

但是,随着项目的增长,将可能需要更复杂的 CSS,最终您的选择器可能变成这样:

.box:nth-last-child(-n+1) .title {
  /* styles */
}

为了确定这些样式如何应用于网页,浏览器实际上必须询问“这是否为有 title 类的元素,其父元素恰好是负第 N 个子元素加上 1 个带 box 类的元素?”浏览器可能需要一些时间来确定这一点。为简化起见,您可以将选择器更改为更具体的类名称:

.final-box-title {
  /* styles */
}

这些替换类名称可能看起来很奇怪,但它们可以让浏览器的工作变得简单得多。例如,在旧版中,如果浏览器要知道某个元素是其类型的最后一个元素,则必须先知道所有其他元素的所有信息,以确定其后面的任何元素是否可能是 nth-last-child。与仅根据类名称将选择器与元素进行匹配相比,这种方法的计算开销可能会高得多。

减少要计算样式的元素数量

另一个性能注意事项(通常比选择器复杂性更重要)是元素更改时需要执行的工作量。

一般来说,计算元素的计算样式的最糟糕的开销情况是元素数量乘以选择器数量,因为浏览器需要对照每个样式对每个元素都检查至少一次,看它是否匹配。

样式计算可以直接定位到少量元素,而不是声明整个页面无效。在现代浏览器中,这往往不再是个问题,因为浏览器并不一定需要检查一项更改可能影响的所有元素。另一方面,较早的浏览器不一定针对此类任务进行了优化。应当尽可能减少声明为无效的元素的数量

衡量样式重新计算的开销

您可以通过以下几种方式衡量浏览器中样式重新计算的开销。这两种方法各有优点,具体取决于您是想在开发环境中的浏览器中衡量,还是想衡量真实用户在您的网站上完成此过程所需的时间。

在 Chrome DevTools 中衡量样式重新计算的开销

测量样式重新计算开销的方法之一是使用 Chrome DevTools 中的“Performance”面板。如需开始使用,请执行以下操作:

  1. 打开 DevTools。
  2. 前往效果标签页。
  3. 选中选择器统计信息复选框(可选)。
  4. 点击录制
  5. 与网页互动。

停止录制后,您会看到如下图所示的内容:

DevTools 显示样式计算。
显示样式计算的 DevTools 报告。

顶部的条状图是迷你火焰图,还会绘制每秒帧数。activity 越靠近条状标签页底部,浏览器绘制帧的速度就越快。如果您看到火焰图在顶部趋于平稳,并且上面有红色条,则表示有工作会导致帧长时间运行。

在 Chrome DevTools 中,在已填充的性能面板的活动摘要中,放大 Chrome DevTools 中的问题区域。
DevTools 活动摘要中的长时间运行的帧。

在滚动等互动期间出现长时间运行的帧值得仔细研究。如果您看到一个大的紫色块,请放大该 activity,然后选择标记为重新计算样式的任何工作,以详细了解可能耗费大量资源的样式重新计算工作。

获取长时间运行的样式计算的详细信息,包括样式重新计算工作影响的元素数量等重要信息。
在 DevTools 摘要中,一项耗时较长的样式重新计算仅需 25 毫秒多一点。

点击相应事件即可显示其调用堆栈。如果渲染工作是由用户互动引起的,则会调用触发样式更改的 JavaScript。它还会显示更改影响的元素数量(本例中刚好超过 900 个元素),以及样式计算所花的时间。您可以使用此信息来开始尝试在代码中查找修正点。

如果您在跟踪之前勾选了效果面板设置中的选择器统计信息复选框,则轨迹底部的面板中会显示一个同名标签页。

CSS 选择器统计信息表,显示在 Chrome 开发者工具的“性能”面板中。此表包含标题和相应数据,例如经过的时间、匹配尝试次数、匹配次数、不匹配节点的百分比、选择器以及可在其中找到选择器的样式表。
选择器统计信息表,如 Chrome DevTools 的“Performance”面板中所示。

此面板会提供有关每个选择器相对开销的实用数据,以便您识别开销较高的 CSS 选择器。

如需了解详情,请参阅 CSS 选择器统计信息文档

衡量真实用户的样式重新计算开销

如果您想知道网站的真实用户需要多长时间才能重新计算样式,Long Animation Frames API 提供了实现此目的所需的工具。此 API 中的数据已添加到 web-vitals JavaScript 库,包括样式重新计算时间。

如果您怀疑互动呈现延迟是导致网页 INP 的主要原因,则需要确定在该时间段内用于重新计算网页样式的比例。如需了解详情,请参阅如何在现场测量样式重新计算时间

资源