【译】较大的 DOM 大小如何影响交互性,以及您可以采取什么措施

avatar

无论如何,当你构建一个网页时,这个网页都会有一个文档对象模型(DOM)。DOM表示页面的HTML结构,使得JavaScript和CSS可以访问页面的结构和内容。

然而,问题在于DOM的大小会影响浏览器快速高效地渲染页面。一般来说,DOM越大,初始渲染页面和后续页面生命周期中更新渲染的成本就越高。

在拥有非常大的DOM的页面中,当修改或更新DOM的交互触发了昂贵的布局操作时,页面的快速响应能力就会受到影响。昂贵的布局操作可能会影响页面的交互到下一次绘制(INP);如果你希望页面对用户的交互能够快速响应,就要确保DOM的大小仅限于所需。

什么时候页面的 DOM太大

了解DOM元素和DOM节点之间的区别非常重要。DOM元素指的是DOM树中的特定HTML元素。DOM节点与DOM元素术语有一定的重叠意义,但其定义扩展到包括注释、空格和文本。虽然Lighthouse DOM尺寸审核中使用的是DOM节点,但在本指南中,尽可能使用DOM元素而非节点。

根据 Lighthouse 的说法,当页面超过 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 元素,内存成本可能会相当大。

所有这些都会影响交互性,但上面列表中的第二项尤为重要。如果交互导致 DOM 发生更改,它可能会启动大量工作,从而导致页面上的 INP 不佳。

如何测量 DOM 大小?

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

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

document.querySelectorAll('*').length;

请注意,上面的代码片段仅包括DOM 中HTML元素的数量。它不包括DOM 中的所有节点。

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

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

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

如果您在实验室中分析您怀疑可能与页面 DOM 大小有关的缓慢交互,您可以通过在分析器中选择标记为“重新计算样式”的任何活动来计算出有多少 DOM 元素受到影响" 并观察底部面板中的上下文数据。

在上面的屏幕截图中,观察到作品的样式重新计算(选中时)显示了受影响元素的数量。虽然上面的屏幕截图显示了 DOM 大小对具有许多 DOM 元素的页面上的渲染工作的影响的极端情况,但此诊断信息在任何情况下都有助于确定 DOM 的大小是否是影响所需时间的限制因素为响应交互而绘制下一帧。

如何减小 DOM 大小?

除了审核您网站的 HTML 以查找不必要的标记之外,减少 DOM 大小的主要方法是减少 DOM 深度。如果您在浏览器开发人员工具的“元素”选项卡中看到如下所示的标记,则表明您的 DOM 可能过深:

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

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

DOM 深度也可能是您使用的框架的症状。特别是,基于组件的框架——例如那些依赖JSX 的框架——需要你在一个父容器中嵌套多个组件。

但是,许多框架允许您通过使用所谓的片段来避免嵌套组件。提供片段作为功能的基于组件的框架包括(但不限于)以下内容:

通过在您选择的框架中使用片段,您可以减少 DOM 深度。如果您担心展平 DOM 结构对样式的影响,您可能会受益于使用更现代(和更快)的布局模式,例如flexboxgrid

其他需要考虑的策略

即使您不遗余力地扁平化您的 DOM 树并删除不必要的 HTML 元素以保持您的 DOM 尽可能小,它仍然可能非常大并开始大量渲染工作,因为它会响应用户交互而发生变化。如果您发现自己处于这种情况,您可以考虑一些其他策略来限制渲染工作。

考虑一种加法方法

首次呈现时,您可能处于页面的大部分最初对用户不可见的位置。这可能是一个延迟加载 HTML 的机会,方法是在启动时省略 DOM 的那些部分,但在用户与需要页面最初隐藏方面的页面部分交互时添加它们。

这种方法在初始加载期间甚至之后都非常有用。对于初始页面加载,您预先承担的呈现工作较少,这意味着您的初始 HTML 负载将更轻,并且呈现速度更快。这将在关键时期为交互提供更多机会,以减少对主线程注意力的竞争。

如果页面的许多部分最初在加载时隐藏,它还可以加速触发重新呈现工作的其他交互。但是,随着其他交互向 DOM 添加更多内容,渲染工作将随着 DOM 在整个页面生命周期中的增长而增加。

随着时间的推移添加到 DOM 可能会很棘手,并且它有其自身的权衡。如果您选择这条路线,您可能会发出网络请求以获取数据以填充您打算添加到页面以响应用户交互的 HTML。虽然正在进行的网络请求不计入 INP,但它会增加感知延迟。如果可能,显示正在获取数据的加载微调器或其他指示器,以便用户了解正在发生的事情。

限制 CSS 选择器的复杂度

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

阅读以了解更多信息: 减少样式计算的范围和复杂性

使用content-visibility属性

CSS 提供了该content-visibility属性,这是一种有效地延迟渲染屏幕外 DOM 元素的方法。当元素接近视口时,它们会按需呈现。这样做的好处content-visibility不仅是在初始页面渲染时减少了大量的渲染工作,而且当页面 DOM 因用户交互而更改时,还可以跳过屏幕外元素的渲染工作。

阅读以了解更多信息:: content-visibility提高渲染性能的新 CSS 属性

结论

将您的 DOM 大小减少到仅是绝对必要的大小是优化网站 INP 的好方法。通过这样做,您可以减少浏览器在更新 DOM 时执行布局和渲染工作所花费的时间。即使不能有效地减小 DOM 大小,也可以使用一些技术将渲染工作隔离到 DOM 子树,例如 CSS 包含和 CSS 属性content-visibility

无论您如何去做,创建一个渲染工作最小化的环境——以及减少您的页面为响应交互所做的渲染工作量——结果将是您的网站在与用户交互时感觉对用户的响应更快. 这意味着您网站的 INP 会更低,这会转化为更好的用户体验。

Hero image from Unsplash, by Louis Reed.

翻译:web.dev/dom-size-an…