衡量软导航

发布时间:2023 年 2 月 1 日;上次更新时间:2026 年 6 月 24 日

自推出以来,Core Web Vitals 计划一直致力于衡量网站的实际用户体验,而不是网站的创建或加载方式背后的技术细节。这三项 Core Web Vitals 指标是以用户为中心的指标,是现有技术指标(例如 DOMContentLoadedload)的改进,这些技术指标衡量的时间往往与用户感知到的网页性能无关。因此,只要网站表现良好,用于构建网站的技术就不应影响得分。

现实情况总是比理想情况复杂一些,而热门的单页应用架构从未获得核心网页指标的完全支持。当用户在网站中浏览时,这些 Web 应用不会加载不同的单个网页,而是使用所谓的“软导航”,即通过 JavaScript 更改网页内容。在这些应用中,通过更改网址并将之前的网址推送到浏览器的历史记录中,可以保持传统网页架构的假象,从而让后退和前进按钮能够按用户预期的方式工作。

许多 JavaScript 框架都使用此模型,但每种框架的使用方式各不相同。由于这超出了浏览器传统上理解的“网页”范围,因此一直难以衡量:如何界定当前网页上的互动,以及何时应将其视为网页?

Chrome 团队已经考虑此挑战有一段时间了,目前正寻求标准化“软导航”的定义,以及如何针对软导航衡量 Core Web Vitals,就像衡量以传统多网页应用 (MPA) 架构实现的网站一样。

我们根据开发者的反馈对提案进行了多项改进,并计划从 Chrome 151 开始推出两项新的性能 API,以帮助解决此问题。

什么是软导航?

我们提出了以下软导航定义:

  • 导航由用户操作发起。
  • 导航会导致用户看到的网址发生变化。
  • 互动会导致出现可见的绘制。

对于某些网站,此定义可能会导致误报(用户实际上不会认为发生了“导航”)或漏报(用户认为发生了“导航”,但实际上不符合这些条件)。欢迎您在软导航规范代码库中提供反馈。

开发者工具对软导航的支持

我们已在跟踪视图中为开发者工具的“性能”面板添加了对软导航的支持:

“性能”面板中的软导航标记,带有来自 youtube.com 的轨迹。

您可以看到软导航和 LCP 的标记,这两者都标有 *,以便将它们与常规的硬导航条目区分开来。此功能默认处于启用状态,与我们接下来要讨论的性能 API 变更无关。此功能可让您快速测试软导航检测功能是否能正常用于您的网站。

目前,此功能仅在轨迹视图中显示软导航和 LCP 时间戳。其他指标(例如 LCP)以及对实时指标视图的支持将在稍后添加。

Chrome 如何为 Web 开发者实现软导航?

启用软导航功能后(下一部分会详细介绍),Chrome 将更改其报告某些性能指标的方式:

  • 每次检测到软导航后,系统都会发出 soft-navigation PerformanceTiming 事件。
  • soft-navigation 条目将包含 navigationIdname 属性中的新网址)以及启动互动的 interactionId
  • 在导致有内容绘制的互动之后,系统会发出一个或多个 interaction-contentful-paint 条目。此对象将包含一个 largestContentfulPaint 条目,可用于衡量软导航的 Largest Contentful Paint (LCP)
  • navigationId 属性已添加到每个性能时间(first-paintfirst-contentful-paintlargest-contentful-paintinteraction-contentful-paintfirst-input-delayeventlayout-shift)。这对应于发出事件时所处的导航条目。请注意,如果这些条目跨越软导航,则可能会包含上一个或下一个 navigationId,具体取决于条目的发出时间。如需详细了解此方面的信息,请参阅针对相应网址报告指标部分。
  • soft-navigation 将包含一个 getLargestInteractionContentfulPaint() 函数,用于检索相应导航的最大 interaction-contentful-paint 条目。然后,该值可用作相应导航的初始 LCP,并且随着观察到更多与该互动相关的 interaction-contentful-paint 条目,该 LCP 随后可以更新。请注意,此属性取代了之前源试用中提供的 largestInteractionContentfulPaint 属性。
  • 在软导航发生之前,可能已经发生了一些 interaction-contentful-paint 条目(如果网址更新直到这些绘制之后才发生)。在这种情况下,getLargestInteractionContentfulPaint() 函数可避免在软导航完成后缓冲并回顾旧条目。请注意,getLargestInteractionContentfulPaint() 返回的条目是发出时最大 interaction-contentful-paint 条目的精确副本,因此该条目可能使用了之前的 navigationId,因为这是发生绘制的时间,但这些绘制应根据新的 navigationId 进行衡量。
  • soft-navigation 条目还将包含 paintTimepresentationTime 作为相应导航的 FCP。
  • 请注意,在进一步互动后,系统也会发出 interaction-contentful-paint 条目,但网址的 LCP 应仅限于与软导航 interactionId 匹配的 interaction-contentful-paint 条目,以排除这些条目,并且仅限于其中的 largestContentfulPaint 属性。

这些更改将允许按每次网页导航来衡量 Core Web Vitals 和一些相关的诊断指标,不过有一些细微差别需要考虑。

在 Chrome 中启用软导航会带来哪些影响?

启用此功能后,网站所有者需要考虑以下一些变化:

  • 通过监控 soft-navigation 条目,可以将效果条目“切分”为每个“导航”。
  • CLS 和 INP 指标已经可以根据您的意愿进行切分,而不是在整个网页生命周期内进行衡量,但软导航功能提供了一种标准化衡量方式,无论使用何种底层技术,都可以衡量这种情况何时发生。
  • largest-contentful-paint 条目在互动时(启动软导航所必需的)最终确定,因此只能用于衡量初始“硬”导航 LCP。这意味着,在衡量软导航时,此设置不会发生变化,因此可以像以前一样衡量初始硬导航的网页加载 LCP。
  • 通过查看交互中发出的新 interaction-contentful-paint 条目中的 largestContentfulPaint 属性,可以衡量软导航的 LCP,但使用此条目时需要考虑一些事项,我们将在本文中讨论这些事项。
  • 请注意,并非所有用户都支持此软导航功能,尤其是对于使用旧版 Chrome 和其他浏览器的用户。请注意,即使某些用户会报告 Core Web Vitals 指标,他们也可能不会报告基于软导航的指标。

请咨询您的 RUM 提供商,了解他们是否支持通过软导航来衡量核心网页指标。许多人正计划测试这一新标准,并将之前的注意事项纳入考虑范围。与此同时,部分提供商还允许根据自己的启发式方法对效果指标进行有限的衡量。

如需详细了解如何衡量软导航的指标,请参阅按软导航衡量 Core Web Vitals 部分

如何在 Chrome 中启用软导航?

软导航功能计划在 Chrome 151 中默认启用,但在此之前,您可以通过明确启用此功能来测试它。

对于开发者,可以通过在 chrome://flags/#soft-navigation-heuristics 处开启相应标志来启用此功能。或者,您也可以在启动 Chrome 时使用 --enable-features=SoftNavigationHeuristics 命令行实参来启用该功能。启用 chrome://flags/#enable-experimental-web-platform-features 标志也会启用软导航。

一些网站所有者还通过源试用流程在网站发布之前就启用了此功能。请注意,在开发该功能的过程中,API 形态发生了变化,并且最终发布的功能与之前的原始试用版存在差异,详情请参阅软导航变更日志

检测软导航 API 支持的功能

您可以使用以下代码来测试是否支持该 API:

if (PerformanceObserver.supportedEntryTypes.includes('soft-navigation')) {
  // Monitor Soft Navigations
}

请注意,supportedEntryTypes 会在首次使用时冻结,因此如果通过注入到网页中的源试用令牌动态添加了软导航支持,则此属性可能会返回原始值,即在激活该功能之前的值。

在这种情况下,在默认情况下尚不支持软导航且处于此过渡状态时,可以使用以下替代方案:

if ('SoftNavigationEntry' in window) {
  // Monitor Soft Navigations
}

如何衡量软导航?

启用软导航检测后,系统将使用 PerformanceObserver API 报告指标,与其他指标一样。不过,对于这些指标,还需要考虑一些额外因素。

报告软导航

您可以使用 PerformanceObserver 来观察软导航。以下是一个代码段示例,用于将软导航条目记录到控制台,包括使用 buffered 选项记录此页面上之前的软导航:

const observer = new PerformanceObserver(console.log);
observer.observe({ type: "soft-navigation", buffered: true });

可用于最终确定上一次导航的完整生命周期页面指标。

针对相应网址报告指标

检测到软导航时,应最终确定上一个网页的 Core Web Vitals,然后针对上一个网址报告这些指标,并针对新网址开始新的监控。

相应 soft-navigation 条目的 name 属性将包含用于报告指标的新网址,而 navigationId 将是相应导航的唯一引用(因为在单页应用的生命周期内,同一网址可能会被多次访问)。

此值应设置为每个 soft-navigation 条目,并用于报告指标,直到收到下一个 soft-navigation 条目。

报告 interaction-contentful-paint 的正确网址

interaction-contentful-paint 条目计算 LCP 时需要考虑一些额外因素,因为并非所有 interaction-contentful-paint 条目都应使用 navigationId 进行映射,并作为相应网址的 LCP 进行报告:

  • 第一个问题是,如果在网址更新之前发生绘制,则可能会在软导航发生之前发出 interaction-contentful-paint 条目。在这种情况下,navigationId 将是旧网址。如果先更新网址,然后完成绘制,则会完成软导航,在这种情况下,系统会先发出 soft-navigation 条目,而 interaction-contentful-paint 将包含新网址。
  • 第二个问题是,interaction-contentful-paint,对于较新的互动,系统将继续发出条目,因为此效果指标的范围不仅限于软导航的 LCP。我们只想考虑 LCP 的软导航加载的绘制,而不考虑后续互动的绘制。

因此,应使用 interactionId 而不是 navigationIdinteraction-contentful-paint 条目映射到 soft-navigation-entries,以获取正确的网址。这样一来,不仅可以处理具有旧 navigationId 的所有条目,还可以滤除不应纳入 LCP 考虑范围的所有 interaction-contentful-paint 条目。

此外,您还应考虑处理 soft-navigation 条目的 getLargestInteractionContentfulPaint() 函数,以便更轻松地处理在发出 soft-navigation entries 之前发生的 interaction-contentful-paint 条目。

获取软导航的 startTime

所有性能时间(包括软导航的时间)以及用于计算 Core Web Vitals 指标的条目都报告为自初始“硬”网页导航时间起的时间。因此,应从软导航加载指标时间(例如 LCP)中减去软导航开始时间,以便报告相对于此软导航时间的时间。

通过映射到相应的 soft-navigation 条目并使用其 startTime,可以类似的方式获取导航开始时间。

startTime 是启动软导航的初始互动(例如点击按钮)的时间。这与“硬导航”略有不同,在“硬导航”中,“开始时间”是指浏览器“提交”新网页的时间,并且是在运行部分事件处理脚本代码之后。由于我们是从互动开始时间开始测量的,因此软导航开始时间也包括该事件处理程序代码。

衡量每次软导航的 Core Web Vitals

如需衡量 Core Web Vitals,请监听 soft-navigation 条目,并在收到这些条目时重置指标。可以根据 presentationTime 发出 FCP,并将 LCP 初始化为 getLargestInteractionContentfulPaint() 条目。INP、CLS 应初始化为 0,就像网页加载时一样。

然后,您可以像往常一样衡量和监控 LCP、INP 和 CLS(但使用 interaction-contentful-paint 衡量 LCP 时,需要提供 interactionId 匹配项)。interactionId 可用于命名网址的条目,如前文所述

时间仍将相对于原始的“硬”导航开始时间返回。因此,若要计算软导航的 LCP,您需要获取 interaction-contentful-paint 时间,然后减去相应的软导航开始时间(如前文所述),以获得相对于软导航的时间。

有些指标一直以来都是在整个网页生命周期内进行衡量的:例如,LCP 在发生互动之前可能会发生变化。在离开网页之前,无论是否发生任何互动,CLS 和 INP 都可以更新。因此,每次发生新的软导航时,都应最终确定上一次导航的指标。这意味着,在通过软导航衡量 Core Web Vitals 时,初始“硬”导航指标可能会比平时更早确定。

同样,当开始衡量这些长期存在的指标的新软导航的指标时,需要“重置”或“重新初始化”指标,并将其视为新指标,而不会记住之前“网页”设置的值。也就是说,系统会重置对“最大”绘制、Interaction to Next Paint 或布局偏移的理解,以便从头开始重新衡量。

在导航之间保持不变的内容应如何处理?

软导航的 LCP(根据 interaction-contentful-paint 计算)将仅衡量新绘制,并且仅衡量与导致导航的互动相关联的绘制。这可能会导致 LCP 不同,例如,从该软导航的冷加载到软加载。

例如,假设某个网页包含一个作为 LCP 元素的大横幅图片,但其下方的文字会随着每次软导航而变化。初始网页加载会将横幅图片标记为 LCP 元素,并以此为依据计算 LCP 时间。对于后续的软导航,下面的文字将是软导航后绘制的最大元素,并将成为新的 LCP 元素。不过,如果网页是通过软导航网址中的深层链接加载的,则横幅图片将是新的绘制,因此可以被视为 LCP 元素。

同样,动画可能会持续更新网页的一部分,这与发生的任何软导航无关。由于该背景动画而产生的任何新绘制都不会被视为新软导航的 LCP。不过,如果网页是从此网址重新加载的,则可能会将这些图片纳入 LCP 考虑范围。

如这些示例所示,软导航的 LCP 元素可能会因网页加载方式而异,就像加载带有锚链接的网页(锚链接位于网页下方)可能会导致硬导航的 LCP 元素有所不同一样。

如何衡量 TTFB?

对于常规网页加载,第一字节时间 (TTFB) 表示返回原始请求的第一个字节所用的时间。

对于软导航,这是一个比较棘手的问题。我们是否应衡量针对新网页发出的第一个请求?如果应用中已包含所有内容,并且没有其他请求,会发生什么情况?如果提前通过预提取发出该请求,会怎么样?如果用户发出的请求与软导航无关(例如,是分析请求),会发生什么情况?

一种更简单的方法是,对于软导航,报告的 TTFB 为 0,这与我们建议的往返缓存恢复类似。这是 web-vitals用于软导航的方法,也是我们目前建议用于此指标的方法。

您是否应该同时使用这两种方法来衡量 Core Web Vitals?

虽然这些新 API 仅限于基于 Chromium 的浏览器,但网站可能希望通过按软导航进行切分来衡量这两者,并继续按硬导航进行切分。这样一来,您就可以跨浏览器进行比较,并查看历史趋势。

对于 LCP,这意味着当前方式只考虑 largest-contentful-paint 条目,而新方式同时考虑 largest-contentful-paintinteraction-contentful-paint 条目。

对于 CLS 和 INP,这意味着需要像当前那样在整个网页生命周期内衡量这些指标,并按软导航分别对时间轴进行切分,以衡量新内容的单独 CLS 和 INP 值。

然后,这些指标需要信标化并存储两次以供分析。

使用 web-vitals 库衡量软导航的 Core Web Vitals

考虑到所有细微差别,最简单的方法是使用 web-vitals JavaScript 库,该库在单独的 soft-navs branch实验性地支持软导航(也可在 npmunpkg 上使用)。您可以通过以下方式衡量此指标(根据需要替换 doTraditionalProcessingdoSoftNavProcessing):

import {
  onTTFB,
  onFCP,
  onLCP,
  onCLS,
  onINP,
} from 'https://unpkg.com/web-vitals@soft-navs/dist/web-vitals.js?module';

function doTraditionalProcessing(callback) {
  ...
}

function doSoftNavProcessing(callback) {
  ...
}

onTTFB(doTraditionalProcessing);
onFCP(doTraditionalProcessing);
onLCP(doTraditionalProcessing);
onCLS(doTraditionalProcessing);
onINP(doTraditionalProcessing);

onTTFB(doSoftNavProcessing, {reportSoftNavs: true});
onFCP(doSoftNavProcessing, {reportSoftNavs: true});
onLCP(doSoftNavProcessing, {reportSoftNavs: true});
onCLS(doSoftNavProcessing, {reportSoftNavs: true});
onINP(doSoftNavProcessing, {reportSoftNavs: true});

web-vitals 库还可确保您报告的指标是针对正确的网址报告的(如前所述),因为它们在提供给回调的条目中同时包含 navigationIdnavigationURL

web-vitals 库会针对软导航报告以下指标:

指标 详细信息
TTFB 报告为 0。
首次内容渲染 (FCP) 相对于触发软导航的互动所对应的软导航开始时间,首次内容绘制的时间。系统不会考虑上一次导航中存在的或与互动无关的现有绘制。
LCP 从触发软导航的互动开始,到发生 Largest Contentful Paint 的时间(相对于软导航开始时间)。之前导航中存在的现有绘制不与互动相关联,因此不予考虑。与往常一样,此值可以继续更新,直到用户离开网页(或软导航),因为只有这样才能最终确定 LCP。
CLS 导航时间之间最大的班次窗口。与往常一样,此指标可以继续更新,直到用户离开网页(或软导航),因为只有这样才能最终确定 CLS。
INP 导航时间之间的 INP。与往常一样,此指标可以继续更新,直到用户离开相应网页(或软导航)为止,因为只有这样才能最终确定 INP。如果没有互动,则不会报告 0 值。

这些更改是否会纳入 Core Web Vitals 的衡量范围?

最终目的是提供一种方法,以便更好地衡量真实用户的体验效果。因此,我们的目标是在 API 推出后,将这些指标纳入所有工具显示的核心网页指标衡量结果中。

我们非常重视 Web 开发者对该 API 的反馈,以及您是否认为该 API 能更准确地反映体验。软导航 GitHub 代码库是提供此类反馈的最佳场所,不过 Chrome 在实现该功能时出现的个别 bug 应在 Chrome 问题跟踪器中提出。

CrUX 中将如何报告软导航?

此功能推出后,CrUX 中将如何确切报告软导航,目前也尚未确定。当我们有更多信息可分享时,会在此处公布 CrUX 的变化。

反馈

我们正在积极征求有关此 API 的反馈,您可以在以下位置提供反馈:

如果您有疑问,也不必过于担心,我们很乐意在上述任一位置收到您的反馈,并会乐于在上述任一位置对问题进行分诊,然后将问题重定向到正确的位置。

更新日志

在开发此 API 的过程中,它发生了一些变化,比稳定版 API 的变化更多。如需了解详情,请参阅软导航变更日志

总结

软导航功能是一种令人兴奋的方法,可用于了解核心网页指标计划如何发展,以衡量我们的指标中缺失的现代网络上的常见模式。我们已从更广泛的网络社区收集了大量反馈,强烈建议对此开发感兴趣的人士利用此机会帮助塑造 API,确保其能够代表我们希望通过此 API 衡量的指标。

致谢

缩略图图片由 Unsplash 用户 Jordan Madrid 提供

这项工作是 Yoav Weiss 在 Google 时首次开展的工作的延续。感谢 Yoav 为此 API 付出的努力。