发布时间:2023 年 2 月 1 日;上次更新时间:2026 年 5 月 14 日
自推出以来,Core Web Vitals 计划一直致力于衡量网站的实际用户体验,而不是网站的创建或加载方式背后的技术细节。这三项 Core Web Vitals 指标是以用户为中心的指标,是对现有技术指标(例如 DOMContentLoaded 或 load)的改进,这些技术指标衡量的时间往往与用户感知到的网页性能无关。因此,只要网站表现良好,用于构建网站的技术就不应影响得分。
现实情况总是比理想情况复杂一些,而热门的单页应用架构从未完全受 Core Web Vitals 的支持。与用户在网站中浏览时加载不同的单个网页不同,这些 Web 应用使用所谓的“软导航”,即通过 JavaScript 更改网页内容。在这些应用中,通过更改网址并将浏览器历史记录中的先前网址推送出去,可以维持传统网页架构的假象,从而让后退和前进按钮能够按用户预期的方式工作。
许多 JavaScript 框架都使用此模型,但每种框架的使用方式各不相同。由于这超出了浏览器传统上理解的“网页”范围,因此一直难以衡量:如何界定当前网页上的互动与新网页之间的界限?
Chrome 团队已经考虑此挑战有一段时间了,目前正寻求标准化“软导航”的定义,以及如何针对软导航衡量 Core Web Vitals,就像衡量以传统多页架构 (MPA) 实现的网站一样。
我们根据开发者在上次源试用中的反馈对 API 进行了一些改进,现在希望开发者在正式发布之前试用最新迭代版本,并就此方法提供反馈。我们对 API 在这些迭代中的表现相当有信心,并计划在今年晚些时候发布该 API,但前提是本次最新的源试用能获得良好的反馈。
什么是软导航?
我们提出了以下软导航的定义:
- 导航由用户操作发起。
- 导航会导致用户看到的网址发生变化。
- 互动会导致可见的绘制。
对于某些网站,此定义可能会导致出现假正例(用户实际上不会认为发生了“导航”)或假负例(用户认为发生了“导航”,但实际上不符合这些条件)。欢迎您在软导航规范代码库中提供反馈。
开发者工具对软导航的支持
我们在跟踪视图中为开发者工具的“性能”面板添加了对软导航的支持:

您可以看到软导航和 LCP 的标记,这两者都标有 *,以便将它们与常规的硬导航条目区分开来。此功能默认处于启用状态,与我们接下来要讨论的性能 API 变更无关。此功能可让您快速测试软导航检测功能是否适用于您的网站。
目前,此功能仅在轨迹视图中显示软导航和 LCP 时间戳。其他指标(例如 LCP)以及实时指标视图中的支持将在稍后添加。
Chrome 如何为 Web 开发者实现软导航?
启用软导航 API 后(下一部分会详细介绍),Chrome 会更改报告某些性能指标的方式:
- 每次检测到软导航后,系统都会发出
soft-navigationPerformanceTiming事件。 - 此
soft-navigation条目将包含navigationId、name属性中的新网址以及启动互动的interactionId。 - 在导致有内容的绘制的互动之后,系统会发出一个或多个
interaction-contentful-paint条目。当互动触发软导航时,此属性可用于衡量软导航的 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将包含一个largestInteractionContentfulPaint条目,其中包含作为导航的一部分发出的最大interaction-contentful-paint条目。然后,该值可用作相应导航的初始 LCP,并且随着观察到更多相应互动的interaction-contentful-paint条目,该 LCP 随后可以更新。- 在软导航发生之前,可能已经出现了一些
interaction-contentful-paint条目(如果网址更新直到这些绘制之后才发生)。在这些情况下,最大的largestInteractionContentfulPaint条目可避免需要缓冲和回顾旧条目。请注意,largestInteractionContentfulPaint是最大interaction-contentful-paint条目的精确副本,因此该条目将使用之前的navigationId,因为这是绘制发生的时间,但这些绘制应根据新的navigationId进行衡量。 soft-navigation条目还将包含paintTime和presentationTime作为相应导航的 FCP。- 请注意,在后续互动后也会发出
interaction-contentful-paint条目,但网址的 LCP 应仅限于与软导航interactionId匹配的interaction-contentful-paint条目,以排除这些条目。
这些更改将允许按每次网页导航来衡量 Core Web Vitals 和一些相关的诊断指标,不过有一些细微差别需要考虑。
在 Chrome 中启用软导航会带来哪些影响?
启用此功能后,网站所有者需要考虑以下一些变化:
- 通过监控
soft-navigation条目,可以将效果条目“切分”为每个“导航”。 - CLS 和 INP 指标已经可以根据您的意愿进行切分,而不是在整个网页生命周期内进行衡量,但软导航 API 提供了一种标准化衡量方式,用于衡量这种情况何时发生,无论使用何种底层技术。
largest-contentful-paint条目在互动时(启动软导航所必需的)最终确定,因此只能用于衡量初始“硬”导航 LCP。这意味着,在衡量软导航时,此设置不会发生变化,因此可以像以前一样衡量初始硬导航的网页加载 LCP。- 从互动中发出的新
interaction-contentful-paint条目可用于衡量软导航的 LCP,但使用此条目时需要考虑一些事项,我们将在本文中讨论这些事项。 - 请注意,并非所有用户都支持此软导航 API,尤其是对于旧版 Chrome 和使用其他浏览器的用户。请注意,即使某些用户报告了 Core Web Vitals 指标,他们也可能不会报告基于软导航的指标。
- 由于这是一项正在开发中的新功能,默认情况下未启用,因此网站应测试此功能,以防出现意外的副作用。
请咨询您的 RUM 提供商,了解他们是否支持通过软导航来衡量核心网页指标。许多人正计划测试这一新标准,并将之前的注意事项纳入考虑范围。与此同时,部分提供商还允许根据自己的启发式方法对效果指标进行有限的衡量。
如需详细了解如何衡量软导航的指标,请参阅按软导航衡量 Core Web Vitals部分。
如何在 Chrome 中启用软导航?
Chrome 中默认未启用软导航,但您可以通过明确启用此功能来进行测试。
对于开发者,可以通过在 chrome://flags/#soft-navigation-heuristics 处开启相应标志来启用此功能。或者,您也可以在启动 Chrome 时使用 --enable-features=SoftNavigationHeuristics 命令行实参来启用该功能。启用 chrome://flags/#enable-experimental-web-platform-features 标志也会启用软导航。
如果某个网站希望为所有访问者启用此功能以了解其影响,则可以从 Chrome 147 开始运行源试用,只需注册该试用并在 HTML 或 HTTP 标头中添加包含源试用令牌的元元素即可启用。如需了解详情,请参阅开始使用源试用一文。
网站所有者可以选择在网页上为所有用户或仅为部分用户启用源试用。请务必了解上述影响部分,以便了解此更改可能会如何影响指标的报告方式,尤其是在为很大一部分用户启用此源试用时。请注意,无论此软导航设置如何,CrUX 都会继续以现有方式报告指标,因此不会受到这些影响。另请注意,源试用还限制为在最多 0.5% 的 Chrome 网页加载(14 天的中位数)中启用实验性功能,但只有非常大的网站才会遇到此问题。
检测软导航 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 将是相应导航的唯一引用(因为在单页应用的生命周期内,同一网址可能会被多次访问)。您可以使用 PerformanceEntry API 查找此信息:
const softNavEntry =
performance.getEntriesByType('soft-navigation').filter(
(entry) => entry.navigationId === navigationId
)[0];
const hardNavEntry = performance.getEntriesByType('navigation')[0];
const navEntry = softNavEntry || hardNavEntry;
const pageUrl = navEntry?.name;
报告 interaction-contentful-paint 的正确网址
从 interaction-contentful-paint 条目计算 LCP 时需要考虑一些额外因素,因为并非所有 interaction-contentful-paint 条目都应使用 navigationId 进行映射并作为相应网址的 LCP 进行报告:
- 第一个问题是,如果在网址更新之前发生绘制,则可能会在软导航发生之前发出
interaction-contentful-paint条目。在这种情况下,navigationId将是旧网址。如果先更新网址,然后完成绘制,则会完成软导航,在这种情况下,系统会先发出soft-navigation条目,而interaction-contentful-paint将包含新网址。 - 第二个问题是,由于此效果指标的范围不仅限于软导航的 LCP,因此系统会继续针对较新的互动发出
interaction-contentful-paint条目。我们只想考虑 LCP 的软导航加载的绘制,而不考虑后续互动的绘制。
因此,应使用 interactionId 而不是 navigationId 将 interaction-contentful-paint 条目映射到 soft-navigation-entries,以获取正确的网址。这样一来,系统不仅会处理具有旧 navigationId 的所有条目,还会滤除不应纳入 LCP 考虑范围的所有 interaction-contentful-paint 条目。
此外,您还应考虑处理 soft-navigation 条目的 largestInteractionContentfulPaint 条目,以便更轻松地处理在发出 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 初始化为 largestInteractionContentfulPaint。INP、CLS 应初始化为 0,就像网页加载时一样。
然后,您可以像往常一样测量和监控 LCP、INP 和 CLS(使用 interaction-contentful-paint 时,LCP 提供 interactionId 匹配项的情况除外)。interactionId 和 navigationId 可用于命名网址的条目,如前文所述。
系统仍会返回相对于原始“硬”导航开始时间的时间。因此,若要计算软导航的 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?
在开发该功能期间,建议您继续以当前方式(基于“硬”网页导航)衡量 Core Web Vitals,因为新实现方式在最终发布之前可能会出现问题或发生变化。这与 CrUX 目前的衡量标准也一致(稍后会详细介绍)。
除了这些指标之外,还应测量软导航,以便您了解未来如何测量这些指标,并有机会向 Chrome 团队提供有关此实现方式在实践中的效果的反馈。这将有助于您和 Chrome 团队在未来打造出更出色的 API。
对于 LCP,这意味着当前方式只考虑 largest-contentful-paint 条目,而新方式同时考虑 largest-contentful-paint 和 interaction-contentful-paint 条目。
对于 CLS 和 INP,这意味着需要像当前那样在整个网页生命周期内衡量这些指标,并按软导航分别对时间轴进行切分,以衡量新网页的单独 CLS 和 INP 值。
使用 web-vitals 库衡量软导航的 Core Web Vitals
考虑到所有细微差别,最简单的方法是使用 web-vitals JavaScript 库,该库在单独的 soft-navs branch 中实验性地支持软导航(也可在 npm 和 unpkg 上使用)。您可以通过以下方式衡量此指标(请根据需要替换 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) | 相对于触发软导航的互动,首次内容绘制时间(相对于软导航开始时间)。系统不会考虑之前导航中存在的或与互动无关的现有绘制。 |
| LCP | 从触发软导航的互动开始,相对于软导航开始时间的 Largest Contentful Paint 时间。系统不会考虑之前导航中存在的或与互动无关的现有绘制。与往常一样,系统会在发生互动或网页转入后台时报告此指标,因为只有在这种情况下才能确定最终的 LCP。 |
| CLS | 导航时间之间最大的班次窗口。与往常一样,只有在网页进入后台时,CLS 才能最终确定。如果没有轮班,则报告的值为 0。 |
| INP | 导航时间之间的 INP。与往常一样,系统会在发生互动时或网页转入后台时报告此指标,因为只有在网页转入后台时,INP 才能最终确定。如果没有互动,则不会报告 0 值。 |
这些更改是否会纳入 Core Web Vitals 的衡量范围?
我们希望先评估这些 API,看看它们是否能更准确地反映用户体验,然后再决定是否将它们纳入 Core Web Vitals 计划。最终目的是提供一种方法,以便更好地衡量真实用户的体验效果。因此,我们的目标是在 API 推出后,将这些指标纳入所有工具显示的核心网页指标衡量结果中。
我们非常重视 Web 开发者对该 API 的反馈,以及您是否认为该 API 能更准确地反映体验。软导航 GitHub 代码库是提供此类反馈的最佳场所,不过 Chrome 在实现该功能时出现的个别 bug 应在 Chrome 问题跟踪器中提出。
CrUX 中将如何报告软导航?
此功能推出后,CrUX 中将如何确切报告软导航,目前也尚未确定。不一定保证它们会像当前“硬”导航一样受到处理。
在某些网页中,就用户而言,软导航几乎与完整网页加载完全相同,而单页应用技术的使用只是一个实现细节。而在另一些情况下,它们可能更像是部分加载的附加内容。
该团队目前正专注于技术实现,以便我们判断此 API 是否成功,因此尚未就这些方面做出任何决定。
反馈
我们正在积极征求有关此 API 的反馈,您可以在以下位置提供反馈:
- 有关该 API 的反馈应以 GitHub 上的问题的形式提出。
- 如果 Chromium 实现中的 bug 尚未列入已知问题,则应在 Chrome 的问题跟踪器中提出。
- 如需提供有关网页指标的一般反馈,请发送电子邮件至 web-vitals-feedback@googlegroups.com。
如果您有疑问,也不必过于担心,我们很乐意在上述任一位置收到您的反馈,并会愉快地对这两个位置的问题进行分诊,然后将问题重定向到正确的位置。
更新日志
在开发此 API 的过程中,它发生了一些变化,比稳定版 API 的变化更多。如需了解详情,请参阅软导航变更日志。
总结
Soft Navigations API 是一种令人兴奋的方法,可用于了解 Core Web Vitals 计划如何发展,以衡量我们的指标中缺失的现代网络上的常见模式。我们已从更广泛的网络社区收集了大量反馈,强烈建议对此开发感兴趣的人士利用此机会帮助塑造 API,确保它能够代表我们希望通过此 API 衡量的指标。
致谢
缩略图图片由 Unsplash 用户 Jordan Madrid 提供
这项工作是 Yoav Weiss 在 Google 时首次开展的工作的延续。感谢 Yoav 在此 API 上付出的努力。