发布时间:2023 年 2 月 1 日,上次更新时间:2026 年 9 月 20 日
自推出以来,Core Web Vitals 计划一直致力于衡量网站的实际用户体验,而不是网站创建或加载背后的技术细节。这三个 Core Web Vitals 指标是作为以用户为中心的指标而创建的,是对现有技术指标(例如 DOMContentLoaded 或 load)的改进,这些技术指标衡量的时间通常与用户对网页性能的感知无关。因此,只要网站性能良好,用于构建网站的技术就不会影响评分。
现实总是比理想情况更棘手,而流行的单页应用架构从未得到 Core Web Vitals 指标的完全支持。这些 Web 应用不会在用户浏览网站时加载不同的单个网页,而是使用所谓的“软导航”,即通过 JavaScript 更改网页内容。在这些应用中,通过更改网址并将之前的网址推送到浏览器的历史记录中,可以维持传统网页架构的假象,从而使后退和前进按钮能够按用户的预期工作。
许多 JavaScript 框架都使用此模型,但方式各不相同。由于这超出了浏览器传统上理解的“网页”范畴,因此衡量起来一直很困难:如何界定当前网页上的互动与新网页上的互动?
Chrome 团队已经考虑这一挑战有一段时间了,并希望对“软导航”的定义进行标准化,以及如何衡量 Core Web Vitals,其方式与衡量采用传统多页架构 (MPA) 实现的网站类似。
我们根据开发者反馈对该提案进行了多项改进,并推出了两个新的性能 API,以帮助从 Chrome 151 开始解决此问题。此外,我们还在 Chrome 用户体验报告 (CrUX) 中提供了软导航指标作为实验性指标。
什么是软导航?
我们对软导航的定义如下:
- 导航由用户操作发起。
- 导航会导致用户看到网址发生变化。
- 互动会产生可见的绘制。
对于某些网站,此定义可能会导致假正例(用户实际上并不认为发生了“导航”)或假负例(尽管不符合这些条件,但用户确实认为发生了“导航”)。欢迎在软导航规范代码库中提供反馈。
开发者工具对软导航的支持
我们为 DevTools “Performance”面板中的实时指标视图添加了对软导航的支持,并在跟踪视图中添加了数据分析和标记支持:
Chrome 如何为 Web 开发者实现软导航?
启用软导航功能后(详见下一部分),Chrome 将更改报告某些性能指标的方式:
- 每次检测到软导航后,系统都会发出
soft-navigationPerformanceTiming事件。 - 此
soft-navigation条目将包含navigationId、name属性中的新网址,以及发起互动的interactionId。 - 在导致内容绘制的互动之后,系统会发出一个或多个
interaction-contentful-paint条目。这将包含一个largestContentfulPaint条目,可用于衡量软导航的 Largest Contentful Paint (LCP)。 navigationId属性会添加到每个性能计时(first-paint、first-contentful-paint、largest-contentful-paint、interaction-contentful-paint、first-input-delay、event和layout-shift)中。这对应于发出事件的导航条目。请注意,当这些条目跨越软导航时,它们可能包含上一个或下一个navigationId,具体取决于条目的发出时间。如需了解详情,请参阅针对适当的网址报告指标部分。soft-navigation将包含一个getLargestInteractionContentfulPaint()函数,用于检索该导航的最大interaction-contentful-paint条目。然后,该 LCP 可用作该导航的初始 LCP,并且随着观察到该互动的更多interaction-contentful-paint条目,该 LCP 随后可以更新。请注意,这会取代之前源试用中提供的largestInteractionContentfulPaint属性。- 在软导航发生之前,可能会发生一些
interaction-contentful-paint条目(如果网址更新在这些绘制之后才发生)。在这些情况下,getLargestInteractionContentfulPaint()函数可避免在软导航完成后缓冲和回顾旧条目。请注意,getLargestInteractionContentfulPaint()返回的条目是发出时最大interaction-contentful-paint条目的精确副本,因此该条目可能使用了之前的navigationId,因为那是绘制发生的时间,但这些绘制应根据新的navigationId进行衡量。 soft-navigation条目还将包含paintTime和presentationTime,作为该导航的 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 151 之前版本的用户。请注意,某些用户可能不会报告基于软导航的指标,即使他们报告了 Core Web Vitals 指标。
请咨询您的 RUM 提供商,了解他们是否支持通过软导航衡量 Core Web Vitals。许多广告主计划测试这一新标准,并会考虑上述因素。与此同时,一些提供商还允许根据自己的启发式方法对效果指标进行有限的衡量。
如需详细了解如何衡量软导航的指标,请参阅“衡量每次软导航的 Core Web Vitals”部分。
如何在 Chrome 中启用软导航?
自 Chrome 151 起,软导航功能默认处于启用状态。
检测 Soft Navigations API 支持的功能
您可以使用以下代码测试是否支持该 API:
if (PerformanceObserver.supportedEntryTypes.includes('soft-navigation')) {
// Monitor Soft Navigations
}
或者:
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 而不是 navigationId 将 interaction-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 条目,并在收到这些条目时重置指标。FCP 可以根据 presentationTime 发出,LCP 可以初始化为 getLargestInteractionContentfulPaint() 条目。INP、CLS 应初始化为 0,就像网页加载时一样。
然后,您可以照常衡量和监控 LCP、INP 和 CLS(但 LCP 使用 interaction-contentful-paint,前提是 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 元素可能会因锚链接在网页中的位置而异。
如何衡量 TTFB?
对于常规网页加载,第一字节时间 (TTFB) 表示返回原始请求的第一个字节的时间。
对于软导航,这个问题更棘手。我们是否应该衡量针对新网页发出的第一个请求?如果所有内容都已存在于应用中,并且没有其他请求,该怎么办?如果该请求是通过预提取提前发出的,会怎么样?如果从用户角度来看,请求与软导航无关(例如,它是分析请求),该怎么办?
一种更简单的方法是,针对软导航报告 TTFB 为 0,这与我们建议的往返缓存恢复方式类似。这是 web-vitals 库用于软导航的方法,也是我们目前针对此指标推荐的方法。
是否应该同时使用这两种方法来衡量 Core Web Vitals?
虽然这些新 API 仅限于基于 Chromium 的浏览器,但网站可能希望通过软导航和硬导航来衡量。这样就可以跨浏览器进行比较,并了解历史趋势。
对于 LCP,这意味着,如果采用当前方式,则只需考虑 largest-contentful-paint 条目;如果采用新方式,则需要同时考虑 largest-contentful-paint 和 interaction-contentful-paint 条目。
对于 CLS 和 INP,这意味着要像当前方式一样,在整个网页生命周期内衡量这些指标,并按软导航单独划分时间轴,以衡量新指标的单独 CLS 和 INP 值。
然后,这些指标需要进行两次信标和存储,以便进行分析。
使用 web-vitals 库衡量软导航的 Core Web Vitals
要考虑所有细微差别,最简单的方法是使用 web-vitals JavaScript 库,该库从 v6.0.0 开始支持软导航。您可以通过以下方式衡量此指标(请酌情替换 doTraditionalProcessing 和 doSoftNavProcessing):
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 库还可确保您针对正确的网址报告指标(如前所述),因为它们在提供给回调的条目中同时包含 navigationId 和 navigationURL。
web-vitals 库会报告以下软导航指标:
| 指标 | 详细信息 |
|---|---|
| TTFB | 报告为 0。 |
| 首次内容渲染 (FCP) | 从触发软导航的互动开始,相对于软导航开始时间的 First Contentful Paint 时间。系统不会考虑之前导航中存在的现有绘制,也不会考虑与互动无关的绘制。 |
| LCP | 从触发软导航的互动开始,到发生最大内容绘制的时间(相对于软导航开始时间)。系统不会考虑上一次导航中存在的、与互动无关的现有绘制。与往常一样,此值可能会持续更新,直到用户离开页面(或软导航),因为只有到那时,LCP 才能最终确定。 |
| INP | 两次导航之间的 INP。与往常一样,此值可能会持续更新,直到用户离开网页(或软导航),因为只有到那时,INP 才能最终确定。如果没有互动,系统不会报告 0 值。请注意,导致软导航的互动通常与之前的导航(导航来源)相关联,而不是与新导航(导航目标)相关联,因为需要首次绘制才能导致软导航。这与硬导航类似,在硬导航中,点击链接可能会产生 INP,但该 INP 会与发生点击的网页相关联。 |
| CLS | 导航时间之间最大的班次窗口。与往常一样,此值可能会持续更新,直到用户离开页面(或软导航),因为只有到那时,CLS 才能最终确定。请注意,与导航事件关联的 CLS 可能会被排除(如果发生在互动后 500 毫秒内),可能与上一个导航关联(如果偏移发生在网址更新之前),也可能与新导航关联(如果偏移发生在软导航完成后)。 |
这些变更会纳入 Core Web Vitals 衡量标准吗?
最终目标是提供一种方法,以便更好地衡量真实用户体验到的性能。因此,我们的目标是在 API 发布后,将这些指标纳入所有工具公开的 Core Web Vitals 衡量指标中。
CrUX 中将如何报告软导航?
我们已在 CrUX 中推出了 Core Web Vitals 指标的实验性版本。这些 API 会在首次软导航后结束“硬导航”CLS 和 INP,并为每次软导航提供额外的 LCP、CLS 和 INP 测量。我们计划于 2027 年 5 月将这些实验性指标升级为稳定指标。如需了解详情,请参阅博文《CrUX 现已推出实验性软导航指标》。
如何在其他浏览器中处理软导航?
在不支持该 API 的浏览器中,很难通过程序化方式检测软导航,而这正是我们开发该 API 的原因。
您可以使用 Navigation API 监控网址更改,以便按网址对 INP 进行切片(CLS 也是如此,但目前仅限 Chromium,因此无论如何都不会进行衡量)。不过,这无法解决只能近似计算的绘制指标(FCP 和 LCP)的问题。
同时,我们认为此 API 提供的分析洞见非常有价值,不容忽视,无论是衡量软导航的时间,还是将指标归因于正确的导航。尽管目前缺乏跨浏览器支持,我们仍建议您使用这个新 API。与 Core Web Vitals 推出时的情况类似,发现的问题和性能解决方案可能会影响所有浏览器,即使目前仅限于基于 Chromium 的浏览器。
我们将继续推进标准化流程,并与其他浏览器供应商合作,展示此 API 的重要性。
反馈
我们正在通过以下渠道积极征求有关此 API 的反馈:
- 有关该 API 的反馈应作为问题在 GitHub 上提出。
- 如果 Chromium 实现中存在 bug,且该 bug 尚未列入已知问题,则应在 Chrome 的问题跟踪器中提出。
- 您可以通过 web-vitals-feedback@googlegroups.com 分享有关 Web Vitals 的一般反馈。
如果您不确定,也不必过于担心,我们更希望在任一位置收到反馈,并且会很乐意在两个位置对问题进行分类,并将问题重定向到正确的位置。
更新日志
随着此 API 的开发,它发生了一些变化,比稳定版 API 的变化更多。如需了解详情,请参阅软导航变更日志。
总结
软导航功能是一种令人兴奋的方法,可帮助 Core Web Vitals 计划不断演变,以衡量现代网络上我们的指标中缺失的常见模式。我们从更广泛的 Web 社区收集了大量反馈,并对该 API 的潜力感到鼓舞。
致谢
缩略图由 Jordan Madrid 在 Unsplash 上发布
这项工作是 Yoav Weiss 在 Google 工作期间首次启动的工作的延续。我们感谢 Yoav 为此 API 做出的努力。