新时代的 Google Web Vitals 性能指标

2021-11-12 15:30:54 浏览数 (1)

作者:Milica Mihajlija 原文:https://calibreapp.com/blog/new-generation-of-performance-metrics 翻译 / 润色:单是昊 来源公众号:ByteDance Web Infra 这是我们 Web Infra APM 团队体验监控相关系列的第一篇文章,后续会持续更新这个专题。记得先加个关注,不迷路。

传统的性能指标如 load time[1]DOMContentLoaded[2] 专注于容易衡量的技术细节,但是它们很难反应出用户所真正关心的是什么。如果你仅仅是把加载速度优化的更快,你很快就会发现网站的用户体验依然很差。一个站点的总加载时间可以很快,但如果它直到所有内容都准备好了才渲染的话,用户只能盯着空白的屏幕一段时间。如果点击了按钮但没有反应,是因为主线程被 JavaScript 任务占满而阻塞了,此时虽然页面已经“加载”,但用户依然会感到沮丧。

和上面的例子相比,这个页面有更长的总加载时间,但是渐进式的渲染内容并且不用过度的 JavaScript 来阻塞主线程。用户体验会更好,但加载时间上却无法反映。

这就是创建用户为中心的性能指标的原因,它们专注于用户视角下的浏览体验。

以用户为中心的性能指标衡量页面显示有用内容的速度,

用户是否可以与之交互,以及这些交互是否流畅且无延迟。

用户对页面是否“快”的看法,会受到加载体验中不同时刻的影响,所以这里有几个指标试图捕捉这一点:

用户体验

指标

发生了吗?

First Paint (FP), First Contentful Paint (FCP)

内容有用吗?

First Meaningful Paint (FMP), Speed Index (SI)

内容可用吗?

Time to Interactive (TTI)

这些指标让我们离衡量用户体验又近了一步,但都不是完美的,业界持续研究和开发用来描述良好用户体验的关键指标。随着对于用户体验的理解的深入和测量能力的增强,指标也同样需要随之进化。

这个过程的结果是三个全新的性能指标,它们填补了用户体验故事中的空白。

  • Largest Contentful Paint (LCP)
  • Total Blocking Time (TBT)
  • Cumulative Layout Shift (CLS)

Largest Contentful Paint

Largest Contentful Paint (LCP) 意味着

最大的内容在可视区域内变得可见的时间点

最大的元素,例如一篇文章中的一大段文字或产品页面上的一张图片,大概就是让你理解页面内容的最有用的元素。经过测试[3],LCP 非常近似于页面主要内容加载的时间点。

在上面的例子中,LCP 大概在 0.8ms 也就是香蕉图片加载完时发生。

为了优化 LCP,确保:

  • 消除阻塞渲染的资源[4]
  • 最小化关键请求链[5],通过以正确的优先级和顺序加载资源。
  • 压缩图像,并为不同的设备提供不同的图像大小。
  • 优化 CSS,压缩文件和提取关键 CSS[6]
  • 使用字体加载策略[7]来避免了不可见文字的闪烁(FOIT)。

为什么我们需要 LCP

浏览器和性能监控工具已经报告绘制指标很长一段时间了。我们的目标一直是衡量用户感知页面加载进度的关键时刻。然而,其中的一些指标据我们所知,有一些明显的缺陷:

指标

定义

问题

First Contentful Paint (FCP)

浏览器绘制第一块 DOM 内容的时间点。

- 通常和用户无关(例如加载指示器或者进度条)

First Meaningful Paint (FMP)

页面加载中产生最剧烈的布局变化后的绘制时间点。

- 非标准化并且难以在浏览器之间统一实现。- 约 20% 的情况下不准确。"

Speed Index (SI)

Speed Index (SI)

- 复杂的指标,难以解释。- 计算密集,所以在主流浏览器中都不可用于真实用户监控(RUM)。"

LCP 则不同:

  • 容易理解。
  • 相关的(给出与SI相似的结果)
  • 在 RUM 工具中容易计算和上报。

事实上 LCP 的出现并不意味着其他指标就是没用的。FCP 依然是相关的,因为它给用户页面实际加载的反馈。关于 FMP 的实验则对 LCP 的发展提供了有价值的见解。

最大内容绘制在 Calibre[8](一个性能监控平台)、Chrome DevTools 或通过 Largest Contentful Paint API[9] 都可以使用。在 Lighthouse(从 6.0 版本开始)中 LCP 会被用来计算性能得分。如果想要学习更多有关如何计算得分、和前一个版本相比有何变化的话,请查看性能得分计算器[10]

Total Blocking Time

Total Blocking Time(TBT) 描述了 JavaScript 主线程活动。

它有助于理解在加载期间,页面无法响应用户输入的时间有多久。

在多数情况下,所有渲染网页[11]的工作、运行 JavaScript 和响应用户输入,都发生在主线程上。当用户在主线程正在处理其他任务时点击了按钮,则响应将被延迟,直到主线程空闲。如果延迟很小,比如小于 50ms 的话,用户甚至不会注意到。如果主线程阻塞更久的话,用户则会感受到页面的的延迟和未响应。

TBT 量化了主线程花费在长任务[12]上的时间,以估计长任务在页面加载过程的过程中潜在的影响用户交互的风险。

什么是长任务?

如果一个任务在主线程上运行超过 50 毫秒,那么它就是长任务。超过 50ms 后的任务耗时,都算作任务的阻塞时间。

一个页面的 Total Blocking Time 总阻塞时间,是从 FCP 到 TTI (Time to Interactive 可交互时间)之间所有长任务的阻塞时间的总和。

下表是上述例子中,TBT 的计算方式:

Task

任务时间

任务阻塞时间(> 50 ms)

1

75ms

25ms

2

25ms

0ms

3

85ms

35ms

4

30ms

0ms

Total Blocking Time

0ms

跟踪 TBT 是改善页面交互性的第一步。如果你注意到 TBT 值过高:

  • 对 JavaScript bundle 进行代码分割,并延迟加载那些对初始加载不重要的包。
  • 可能的话,将代码分解成工作更少、执行更快的函数。
  • 减少频繁的 DOM 查询。
  • 将计算密集型任务交给 Service workers 或 Web workers。

Total Blocking Time 和 Time To Interactive 的区别?

Time to Interactive (TTI)[13] 可交互时间衡量页面何时可以可靠的响应用户的输入。如果页面的主线程上至少 5 秒都没有长任务,那么可以认为它是“完全可交互的”。

Total Blocking Time 总阻塞时间,只在 FCP 和 TTI 之间计算。

TTI 识别主线程何时变为空闲状态。

TBT 量化主线程在空闲之前的繁忙程度。

TTI 有时可能会误导用户,但当与 TBT 结合使用时,您就会更清楚地了解页面对用户输入的响应程度。

例如,两个页面可以有相同的TTI,但如果其中一个页面将工作分解成更小的任务,而另一个页面的主线程上一直占满了一个很长的任务,那么第二种情况下的用户体验将会更差。这种差异将反映为高得多的 TBT,如下图所示:

在 Calibre 和 Lighthouse 中都有Total Blocking Time 指标,和LCP一样,TBT也会在 Lighthouse 6.0 以上被加入性能分数计算。

Cumulative Layout Shift

累积布局偏移(CLS)量化了

在页面加载期间,视口中有多少元素移动。

这里有个例子,移动内容(提示元素在页面顶部加载,并将页面内容向下移动)可能会让用户错过他们想要点击的按钮:

更糟糕的是,这种内容偏移可能会导致用户点到他们本不想点击的按钮。

这里有另一个例子,页面内容移动几个像素会引起相当大的麻烦:

一个演示布局稳定性对用户负面影响的截屏。来源:web.dev[14]

无论是以一种增加意外点击几率的方式加载广告,还是在加载新闻图片时文本向下移动,内容的意外移动都会让人非常不舒服。

Cumulative Layout Shift[15] 通过测量它对用户发生的频率,来帮助您解决这个问题。它引入了用户体验中一个全新的类别 —— 可预测性。

下面是一些常见的布局不稳定问题,以及它们的解决方法:

  • 对于没有指定尺寸的图像,浏览器会先渲染一个 1x1 像素的占位直到整个图片下载完成,一旦图像渲染,它会导致布局的其余部分发生变化。为了避免这个问题,可以为 img 元素添加 width 和 height 属性[16]
  • 在渲染内容之后异步获取数据然后插入,可能会导致布局变化。这种情况下,一种比较好的实践是用内容占位符,这样真正内容加载后布局就不会产生太大的变化。
  • 广告通常是异步加载的,在加载时可能会取代其他内容。如果这导致了意外点击,那就更令人心烦了,所以最好提前定义广告空间的尺寸。
  • 利用某些 CSS 属性做动画可能会导致布局变化[17],在大部分情况下,你可以用 transform 属性做动画来避免它。
  • 当利用font-display: swap来进行新旧字体切换时,由于字体之间的大小差异,当新字体加载并替换后备字体时,页面布局通常会发生变化。为避免此问题,你可以在 font-style-matche[18]r 调整不同字体的尺寸,以减小字体切换对布局的影响。

测量累积布局偏移

当渲染的元素在页面加载期间移动时,它们会被标记为不稳定,并且它们在相对于视口的移动决定了布局偏移分数。CLS 仍然在积极开发中,具体的公式可能会变,但目前来说,布局偏移的分数是由以下因素决定的:

  • 不稳定元素移动的距离 —— 距离系数。
  • 受不稳定元素影响的区域面积 —— 影响系数。

紫色箭头代表距离系数,蓝色矩形代表影响系数

在上面的例子中,元素向下移动了视口高度的 ⅓,所以距离系数是 0.33

元素在其起始位置和移动后的位置所占的面积占视口总面积的 ⅔,因此影响分数为 0.66

代码语言:javascript复制
layout shift score = distance fraction * impact fraction

布局偏移得分为 0.33 × 0.66 = 0.2178

累积布局偏移分数,是所有不稳定元素在页面加载期间移动的分数之和。

CLS分数越低越好,因为这意味着

在页面加载过程中发生的内容的偏移较少。

如果上面例子中的元素只相对视口移动了 10%,那么距离系数就是 0.1,影响系数是 0.4。布局偏移得分就仅为 0.1 × 0.4 = 0.04

一个理想但不现实的情况是,CLS 得分为 0。在现实中的 Chrome 用户体验报告中,CLS 分数小于 5 即可被认为是理想的。不同类型的网站可能会有目的的移动内容[19]。此时的高 CLS 分数并不意味着糟糕的用户体验。任何情况下,监测 CLS 都有助于发现预期之外的布局偏移增长并且修复布局不稳定的问题[20]

CLS 已经在 Chrome 用户体验报告中可用,你也可以在 JavaScript 中通过 Layout Instability API 测量 CLS[21]。Calibre 和 Lighthouse 也会加入这个能力。

通过跟踪现代 Web 性能指标来提升客户体验

选用你趁手的性能监控武器,自动化的性能监控是跟踪优化和捕获回归问题的关键。有了现代 Web 指标提供的思路,你可以不断的完善用户体验,并创造出伟大的产品。

参考资料

[1]

load time: https://developer.mozilla.org/en-US/docs/Web/Events/load

[2]

DOMContentLoaded: https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event

[3]

经过测试: https://calendar.perfplanet.com/2019/developing-the-largest-contentful-paint-metric/

[4]

阻塞渲染的资源: https://web.dev/render-blocking-resources/

[5]

最小化关键请求链: https://calibreapp.com/blog/critical-request

[6]

提取关键 CSS: https://web.dev/extract-critical-css/

[7]

字体加载策略: https://www.zachleat.com/web/comprehensive-webfonts

[8]

Calibre: https://calibreapp.com/

[9]

Largest Contentful Paint API: https://wicg.github.io/largest-contentful-paint/

[10]

性能得分计算器: https://paulirish.github.io/lh-scorecalc/

[11]

渲染网页: https://calibreapp.com/blog/investigate-animation-performance-with-devtools#demystifying-rendering

[12]

长任务: https://web.dev/long-tasks-devtools/#what-are-long-tasks

[13]

Time to Interactive (TTI): https://calibreapp.com/blog/time-to-interactive

[14]

web.dev: https://web.dev/cls/

[15]

Cumulative Layout Shift: https://calibreapp.com/blog/cumulative-layout-shift

[16]

可以为 img 元素添加 width 和 height 属性: https://www.youtube.com/watch?v=4-d_SoCHeWE&feature=youtu.be

[17]

利用某些 CSS 属性做动画可能会导致布局变化: https://calibreapp.com/blog/investigate-animation-performance-with-devtools#layers-and-compositing

[18]

font-style-matche: https://meowni.ca/font-style-matcher/

[19]

可能会有目的的移动内容: https://web.dev/cls/#vs.

[20]

修复布局不稳定的问题: https://dev.to/chromiumdev/fixing-layout-instability-176c

[21]

在 JavaScript 中通过 Layout Instability API 测量 CLS: https://dev.to/chromiumdev/measuring-cumulative-layout-shift-cls-in-webpagetest-5cle

0 人点赞