DOM 大小对互动的影响以及应对措施

DOM 大小对互动的影响可能比您想象的更大。本指南将说明原因和可采取的措施。

没有办法解决:当您构建网页时,该网页会具备文档对象模型 (DOM)。DOM 代表网页 HTML 的结构,可让 JavaScript 和 CSS 访问网页的结构和内容。

不过,其中的问题在于 DOM 的大小会影响浏览器快速、高效地渲染网页的能力。一般来说,DOM 越大,最初渲染该网页并在后续网页生命周期中更新渲染的开销就越大。

当修改或更新 DOM 的交互会触发开销非常大的布局工作,进而影响网页快速响应时,就会成为问题。繁琐的布局工作可能会影响网页的互动到下一次绘制 (INP);如果您希望网页能够快速响应用户互动,请务必确保 DOM 大小仅在必要时适用。

何时页面的 DOM 过大?

根据 Lighthouse 报告,当页面的 DOM 大小超过 1,400 时,其 DOM 大小会过大。当页面的 DOM 超过 800 个节点时,Lighthouse 将开始发出警告。以下面的 HTML 为例:

<ul>
  <li>List item one.</li>
  <li>List item two.</li>
  <li>List item three.</li>
</ul>

上面的代码中有四个 DOM 元素:<ul> 元素及其三个 <li> 子元素。您的网页上几乎肯定会有很多节点,因此请务必了解您可以采取什么措施来保持 DOM 大小,并了解在尽可能缩小网页 DOM 后如何优化呈现工作的其他策略。

大型 DOM 对网页性能有何影响?

大型 DOM 会在以下几个方面影响网页性能:

  1. 在网页首次呈现期间。将 CSS 应用于页面后,系统会创建一个与 DOM 类似的结构,称为“CSS 对象模型 (CSSOM)”。随着 CSS 选择器特异性提高,CSSOM 变得更加复杂,需要更多时间来运行必要的布局、样式、合成和绘制工作,以将网页绘制到屏幕上。对于在网页加载初期发生的互动,这项额外的工作会增加互动延迟时间。
  2. 当互动通过插入或删除元素或者修改 DOM 内容和样式来修改 DOM 时,渲染该更新所需的工作可能导致成本高昂的布局、样式设置、合成和绘制工作。与网页初次呈现时的情况一样,当 HTML 元素通过互动插入到 DOM 时,CSS 选择器特异性的提升会增加呈现工作量。
  3. 当 JavaScript 查询 DOM 时,对 DOM 元素的引用会存储在内存中。例如,如果您调用 document.querySelectorAll 以选择页面上的所有 <div> 元素,那么当结果返回大量 DOM 元素时,内存开销可能会非常大。
因 Chrome 开发者工具的性能面板中的渲染工作过多而导致长时间运行的任务的屏幕截图。这个长任务的调用堆栈显示了重新计算页面样式和预绘制所花费的大量时间。
Chrome 开发者工具中的性能分析器中显示的一项较长任务。显示的耗时较长任务是通过 JavaScript 将 DOM 元素插入大型 DOM 引起的。

所有这些因素都会影响互动,但上述列表中的第二项特别重要。如果互动导致 DOM 发生更改,就会启动大量工作,从而导致网页上的 INP 不佳。

如何测量 DOM 大小?

您可以通过多种方式测量 DOM 的大小。第一个方法使用 Lighthouse。当您执行审核时,当前网页的 DOM 统计信息将显示在“避免 DOM 规模过大”审核下的“诊断”标题下。在此部分中,您可以看到 DOM 元素的总数、包含最多子元素的 DOM 元素以及最深的 DOM 元素。

一种比较简单的方法是,在任何主流浏览器的开发者工具中使用 JavaScript 控制台。要获取 DOM 中 HTML 元素的总数,可在页面加载后在控制台中使用以下代码:

document.querySelectorAll('*').length;

如果您想实时查看 DOM 大小更新,也可以使用性能监控工具。使用此工具,您可以将布局和样式设置操作(以及其他性能方面)与当前 DOM 大小相关联。

Chrome 开发者工具中的性能监控器的屏幕截图。左侧是网页性能的各个方面,您可以在网页生命周期中持续监控。在屏幕截图中,系统正积极监控每个部分的 DOM 节点数、每秒布局数和样式重新计算次数。
Chrome 开发者工具中的性能监控器。在此视图中,网页当前的 DOM 节点数量与每秒执行的布局操作和样式重新计算一起绘制成图表。

如果 DOM 的大小接近 Lighthouse DOM 大小的警告阈值或完全失败,下一步是弄清楚如何减小 DOM 的大小,以提升网页响应用户互动的能力,从而改善网站的 INP。

如何衡量受互动影响的 DOM 元素数量?

如果您要分析实验室中某个速度缓慢的交互(您怀疑该交互可能与页面 DOM 的大小有关),则可以在性能分析器中选择标记为“Recalculate Style”的任意部分 Activity,并观察底部面板中的上下文数据,从而确定受影响的 DOM 元素数量。

Chrome 开发者工具性能面板中选定样式重新计算活动的屏幕截图。在顶部,互动跟踪显示了点击互动,大部分工作用于执行样式重新计算和预绘制工作。底部有一个面板显示所选活动的更多详细信息,报告称有 2,547 个 DOM 元素受到影响。
观察在 DOM 中因样式重新计算工作而受影响的元素数量。请注意,互动轨道中互动的阴影部分表示超过 200 毫秒的互动时长的部分,这是 INP 的指定“良好”阈值

请注意,在上面的屏幕截图中,选择后,重新计算作品的样式会显示受影响元素的数量。虽然上面的屏幕截图展示了 DOM 大小对包含许多 DOM 元素的页面渲染工作影响的极端情况,但无论在什么情况下,此诊断信息都很有用,可以确定 DOM 大小是否是影响下一帧绘制响应响应所需时间的限制因素。

如何缩减 DOM 大小?

除了审查网站的 HTML 以消除不必要的标记之外,减小 DOM 大小的主要方式是减少 DOM 深度。如果您看到与浏览器开发者工具的元素标签类似的标记,就表示 DOM 太深了,可能不够深:

<div>
  <div>
    <div>
      <div>
        <!-- Contents -->
      </div>
    </div>
  </div>
</div>

看到这样的模式时,您可以通过扁平化 DOM 结构来简化它们。这样做可以减少 DOM 元素的数量,并可能让您有机会简化网页样式。

DOM 深度还可能是您使用的框架的表现。特别是,基于组件的框架(例如依赖于 JSX 的框架)需要您在父级容器中嵌套多个组件。

不过,许多框架都支持通过使用 fragment 来避免嵌套组件。提供 fragment 作为功能的基于组件的框架包括(但不限于):以下几项:

通过在所选框架中使用片段,您可以减少 DOM 深度。如果您担心扁平化 DOM 结构对样式设置的影响,建议您使用更现代(且速度更快)的布局模式,例如 flexboxgrid

可以考虑的其他策略

即使您费心将 DOM 树扁平化并移除不必要的 HTML 元素以尽量缩小 DOM,但模型仍然可能相当庞大,并且会随着用户互动而发生变化,进而启动大量渲染工作。如果您发现自己处于这种情况,可以考虑采用一些其他策略来限制渲染工作。

考虑添加方法

有时,当您首次呈现网页时,用户也许无法一开始就看到您网页的大部分内容。这可以通过在启动时省略 DOM 的这些部分来延迟加载 HTML,但要在用户与页面最初需要隐藏的方面进行互动的部分进行互动时再添加这些部分。

这种方法在初始加载期间甚至之后都很有用。初始网页加载时,前期呈现工作量会减少,这意味着初始 HTML 有效负载将更轻,且呈现速度会更快。这将使该关键时期的互动有更多机会运行,而不会增加对主线程注意力的竞争。

如果网页的许多部分最初在加载时处于隐藏状态,那么这也会加快触发重新渲染工作的其他互动的速度。不过,随着其他互动向 DOM 添加更多内容,呈现工作也会随着 DOM 在整个网页生命周期内不断增长而增加。

随着时间的推移,向 DOM 添加内容可能很复杂,并且它有自己的取舍。如果您采用这种方式,则可能会发出网络请求以获取数据,从而填充您打算添加到页面中的 HTML,以响应用户互动。虽然传输中的网络请求不计入 INP,但可能会增加感知延迟时间。如果可能,请显示加载旋转图标或其他指示元素,表明正在获取数据,让用户了解相应操作正在发生。

限制 CSS 选择器的复杂性

当浏览器解析 CSS 中的选择器时,它必须遍历 DOM 树,以了解这些选择器如何以及是否应用于当前布局。这些选择器越复杂,浏览器执行网页初始呈现的工作就越多;当网页因互动而发生变化时,样式重新计算和布局的工作也会增加。

使用 content-visibility 属性

CSS 提供了 content-visibility 属性,该属性实际上是一种延迟渲染屏幕外 DOM 元素的方式。当元素接近视口时,系统会按需渲染这些元素。content-visibility 的优势不仅能减少首次呈现网页时所需的渲染工作量,还能在因用户互动而导致网页 DOM 发生更改时,跳过屏幕外元素的渲染工作。

总结

将 DOM 大小缩减至严格必要的大小有助于优化您网站的 INP。这样,当 DOM 更新时,您可以减少浏览器执行布局和渲染工作所需的时间。即使您无法有效缩减 DOM 大小,您也可以使用一些技术(例如,CSS 包含和 content-visibility CSS 属性)将渲染工作隔离到 DOM 子树中。

无论采用哪种方法,您都需要创建一个可最大限度减少呈现工作的环境,同时减少网页为响应互动而执行的渲染工作量,这样在用户与用户互动时,您的网站的响应速度会更快。这意味着您网站的 INP 将会降低,这也有助于提升用户体验。

主打图片来自 Unsplash 用户,作者:Louis Reed