Web 页面性能衡量指标-以用户为中心的性能指标

以用户为中心的性能指标是理解和改进站点体验的关键点

一、以用户为中心的性能指标

1. 指标是用来干啥的?

指标是用来衡量性能和用户体验的

2. 指标类型

  • 感知加载速度:网页可以多快地加载网页中的所有视觉元素并将其渲染到屏幕上

  • 加载响应速度:页面加载和执行组件快速响应用户互动所需的 JavaScript 代码的速度

  • 运行时响应速度:网页在加载后对用户互动的响应速度

  • 视觉稳定性:页面上的元素是否会以用户意想不到的方式发生偏移,是否可能会干扰用户的互动?

  • 流畅性:过渡和动画是否以一致的帧速率渲染,并在一种状态之间流畅地流动?

3. 要衡量的指标

3.1. FCP(First Contentful Paint)

从网页开始加载到网页内容的任何部分呈现在屏幕上所用的时间

3.2. LCP(Largest Contentful Paint)

从网页开始加载到屏幕上呈现最大的文本块或图片元素所用的时间

3.3. INP(Interaction to Next Paint)

与网页进行的每次 tapclick 或键盘互动的延迟时间

并根据交互的数量选择页面中最差的交互延迟作为单个代表性值来描述页面的总体响应性

3.4. TBT(Total Blocking Time)

FCP 到可交互时间 (TTI) 之间的总时长

3.5. CLS(Cumulative Layout Shift)

从页面开始加载到其生命周期状态更改为隐藏期间发生的所有意外布局偏移的累计分数

3.6. TTFB(Time to First Byte)

网络使用资源的第一个字节响应用户请求所花费的时间

3.7. FID(First Input Delay)

用户首次与网页互动(即,点击链接、点按按钮或使用由 JavaScript 提供支持的自定义控件)到浏览器实际能够开始处理事件处理脚本以响应相应互动的时间

二、FCP(First Contentful Paint )

1. 什么是 FCP?

FCP:从网页开始加载到网页内容的任何部分呈现在屏幕上所用的时间。

首次内容绘制 (FCP) 是一项以用户为中心的重要指标,用于衡量感知的加载速度。

它标记了网页加载时间轴中用户可以看到屏幕上任何内容的第一个点。

FCP 衡量的是从用户首次导航到相应网页到该网页的任何部分呈现在屏幕上所用的时间。对于此指标,内容是指文本、图片(包括背景图片)、<svg> 元素或非白色 <canvas> 元素。

2. FCP

image

FCP 在第二帧发生,因为这是第一个文本元素渲染到屏幕上的时间

3. 良好的 FCP 是多少时间?

为了提供良好的用户体验,网站的 FCP 最好不超过 1.8 秒。

较好的 FCP 值为 1.8 秒或更短。较差超过 3.0 秒。

image

4. 如何衡量 FCP?

5. 衡量 JS 中的 FCP

如需在 JavaScript 中测量 FCP,需使用 Paint Timing API

5.1. 简单示例:

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
    console.log('FCP candidate:', entry.startTime, entry);
  }
}).observe({type: 'paint', buffered: true});

image

5.2. 指标与 API 的区别

  • API 会为后台标签页中加载的网页分派 first-contentful-paint ,但在计算 FCP 时应忽略这些网页。只有当网页始终在前台运行时,系统才会考虑首次渲染时间。

  • 从往返缓存中恢复网页时,API 不会报告 first-contentful-paint ,但在这些情况下,应衡量 FCP,因为用户将它们视为不同的网页访问。

  • API 可能不会报告跨源 iframe 的绘制时间,但为了正确衡量 FCP,必须考虑所有帧。子帧可以使用该 API 将其绘制时间报告给父帧以进行汇总。

  • API 从导航启动时开始测量 FCP,但对于预渲染的网页,应通过 activationStart 测量 FCP

5.3. 使用 web-vitals JavaScript 库来衡量 FCP

使用 web-vitals JavaScript 库来衡量 FCP,而无需记住所有这些细微差异,该库会尽可能处理这些差异

import {onFCP} from 'web-vitals';

onFCP(console.log);

onFCP 源码

6. 如何提高 FCP?

6.1. 提高特定网站的 FCP

可以运行 Lighthouse 性能审核,并关注审核建议的任何特定 opportunities 或者 diagnostics

6.2. 总体提高 FCP

  • 移除阻塞渲染的资源

  • 缩减 CSS 大小

  • 移除未使用的 CSS

  • 移除未使用的 JavaScript

  • 预先连接到所需的源

  • 缩短服务器响应时间 (TTFB)

  • 避免多次网页重定向

  • 预加载密钥请求

  • 避免网络负载庞大

  • 采用高效的缓存政策提供静态资源

  • 避免 DOM 规模过大

  • 最大限度地缩短关键请求深度

  • 确保文本在网页字体加载期间保持可见状态

  • 尽量减少请求数量,减少传输大小

三、LCP(Largest Contentful Paint )

1. 什么是 LCP?

LCP:从网页开始加载到屏幕上呈现最大的文本块或图片元素所用的时间

LCP 报告的是窗口中可见最大图片或文本块相对于用户首次导航到网页的呈现时间

LCP 包含从上一个网页开始的所有卸载时间、连接设置时间、重定向时间和首字节时间 (TTFB)

2. 良好的 LCP 是多少时间?

为了提供良好的用户体验,网站应努力将 LCP 控制在 2.5 秒以内。

image

2.5 s 或者更短

3. 需要考虑哪些元素?

Largest Contentful Paint 考虑的元素类型包括:

  • <img> 元素(第一帧呈现时间用于 GIF 或动画 PNG 等动画内容)

  • <svg> 元素内的 <image> 元素

  • <video> 元素(系统会使用视频的海报图片加载时间或第一帧显示时间,以较早者为准)

  • 一个元素,带有使用 url() 函数加载的背景图片

  • 包含文本节点或其他内嵌级文本元素子元素的块级元素。

后面可能会增加其他元素

4. 如何确定元素的大小?

LCP 报告的元素的大小通常是用户在窗口中可见的大小,如果元素延伸到窗口之外,或者元素被剪切或有不可见的溢出,这些部分不计入元素的大小。

对于根据固有尺寸调整过大小的图片元素,报告的尺寸为可见尺寸或固有尺寸(以较小者为准)。

对于文本元素,LCP 只会考虑能够包含所有文本节点的最小矩形。

对于所有元素,LCP 都不会考虑使用 CSS 应用的外边距、内边距或边框。

5. 什么时候报告 LCP?

网页通常会分阶段加载,因此,网页上最大的元素可能会发生变化。

为了应对这种可能发生的变化,浏览器在绘制完第一帧后,会立即分派 largest-contentful-paint 类型的 PerformanceEntry,用于标识链接最大的内容元素,在渲染后续帧后,只要最大内容元素发生变化,它就会再分派一个 PerformanceEntry

元素只有在呈现并对用户可见后,才能被视为最大的内容元素。尚未加载的图片不会被视为已渲染。在字体屏蔽期间,文本节点也不会使用网页字体。在这种情况下,系统可能会将较小的元素报告为最大的内容元素,但如果这个较大的元素呈现完毕,系统便会创建另一个 PerformanceEntry

除了延迟加载图片和字体之外,网页还可能会在新内容可用时向 DOM 添加新元素。如果这些新元素中的任何一个大于之前的最大内容元素,系统还会报告新的 PerformanceEntry

如果从窗口甚至 DOM 中移除了最大的内容元素,除非渲染了较大的元素,否则它仍然是最大的内容元素

一旦用户与网页互动(通过点按、滚动或按键),浏览器就会停止报告,因为用户互动通常会改变向用户显示的内容(特别是滚动时)。

6. 如何衡量 LCP?

7. 在 JS 中衡量 LCP

7.1. 简单示例

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime, entry);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});

image

7.2. 指标与 API 的区别

  • API 将为后台标签页中加载的页面分派 largest-contentful-paint,但在计算 LCP 时应忽略这些页面。

  • 在页面进入后台后,API 将继续分派 largest-contentful-paint,但在计算 LCP 时应忽略这些(只有在页面始终在前台运行时才可以考虑元素)。

  • 从往返缓存中恢复网页时,该 API 不会报告 largest-contentful-paint ,但应在在这些情况下衡量 LCP ,因为用户对它们的访问体验是不同的。

  • API 不会考虑 iframe 中的元素,但该指标会考虑,因为它们是网页用户体验的一部分。

  • API 从导航开始就测量 LCP,但对于预渲染的网页,LCP 应从 activationStart 开始测量,因为 LCP 对应于用户实际体验到的 LCP 时间。

7.3. 使用 web-vitals JavaScript 库衡量 LCP

可以使用 web-vitalsJavaScript来衡量 LCP,而无需记住所有这些细微差异

import {onLCP} from 'web-vitals';

onLCP(console.log);

onLCP 源码

8. 如何提高 LCP?

  • 消除加载延迟
  • 消除元素渲染延迟
  • 缩短资源加载时长
  • 缩短第一个字节所用的时间

四、INP(Interaction to Next Paint )

1. 什么是 INP?

INP:与网页进行的每次 tapclick 或键盘互动的延迟时间

良好的响应速度意味着网页对互动的响应速度很快。

当网页响应互动时,浏览器会在所绘制的下一帧中提供_视觉反馈。

有些互动自然会比其他互动花费更长的时间,但对于特别复杂的互动,必须快速提供一些初始视觉反馈,让用户知道正在发生的事情。

INP 的目的不是测量互动的所有最终效果,而是下一次绘制被阻止的时间。通过延迟视觉反馈,用户可能会觉得页面响应速度不够快,而 INP 旨在帮助开发者衡量这部分用户体验。

2. INP

image

3. 良好的 INP 是多少时间?

一般 200 ms 以内

  • INP 低于或等于 200 毫秒表示网页响应良好

  • INP 高于 200 毫秒且低于或等于 500 毫秒表示网页的响应能力需要改进

  • INP 高于 500 毫秒表示网页响应速度很差

image

4. 什么是互动?

image

互动的主要驱动因素通常是 JavaScript,但浏览器确实会通过并非由 JavaScript 提供支持的控件(例如复选框、单选按钮和由 CSS 提供支持的控件)提供互动性。
INP 而言,只观察以下互动类型

  • 使用鼠标点击。
  • 点按带有触摸屏的设备。
  • 按实体键盘或屏幕键盘上的某个键。

互动发生在主文档或文档内嵌的 iframe 中。

系统会在用户离开页面时计算该页面的 INP。结果会得到一个能够代表网页在其整个生命周期内的整体响应能力的值。INP 较低意味着网页能够可靠地响应用户输入。

5. INP 与 First Input Delay (FID) 有何不同?

INPFirst Input Delay (FID) 的继任指标。虽然两者都是响应速度指标,但 FID 仅衡量了网页上首次互动的输入延迟。INP 通过观察网页上的所有互动来改进 FID,即从输入延迟开始,到运行事件处理脚本所需的时间,再到浏览器绘制下一帧。
这些差异意味着 INPFID 是不同类型的响应能力指标。FID 是用于评估网页对用户的首次展示的加载响应速度指标,而无论网页互动在何时发生,INP 都是更可靠的整体响应能力指标。

6. 如果未报告 INP 值,该怎么办?

网页可能不会返回任何 INP 值。导致这种情况的原因可能有很多,其中包括以下原因:

  • 页面已加载,但用户从未点击、点按或按键盘上的键。
  • 网页已加载,但用户使用不衡量的手势与网页互动。
  • 该网页正被机器人访问,但该机器人尚未编写与该网页交互的脚本。

7. 如何改进 INP?

  • 优化耗时较长的任务

  • 优化输入延迟

  • 脚本评估和耗时较长的任务

  • 使用 Web Worker 在浏览器的主线程之外运行 JavaScript

  • 避免大型、复杂的布局和布局抖动

  • 缩小样式计算的范围并降低其复杂性

五、 TBT(Total Blocking Time)

1. 什么是 TBT?

TBT:总阻塞时间,从 FCP可交互时间 (TTI) 之间的总时长,其中主线程处于阻塞状态的时间足够长,足以阻止输入响应能力。

每当存在长任务(一种在主线程上运行时间超过 50 毫秒 (ms) 的任务)时,主线程就会被视为阻塞。

我们说主线程处于阻塞状态,因为浏览器无法中断正在进行的任务。如果用户尝试在耗时较长的任务过程中与页面互动,浏览器必须等待任务完成才能响应。

如果主线程处于阻塞状态的时间超过 50 毫秒,用户很可能会注意到延迟,并认为网页运行缓慢或损坏。

2. 良好的 TBT 是多少时间?

网站的 TBT 应低于 200 毫秒。

TBT 时间(以毫秒为单位) 颜色编码
0 - 200 绿色(快速)
200-600 橙色(中等)
600 多个 红色(慢)

3. 如何提高 TBT

  • 将所有工作拆分为运行时间不超过 50 毫秒的代码块,并在合适的位置和时间运行这些代码块。

  • 降低第三方代码的影响

  • 缩短 JavaScript 执行时间

  • 去除不必要的 JS 加载、解析、执行

  • 尽量减少主线程工作

  • 尽量减少请求数量,减少传输大小

六、 CLS(Cumulative Layout Shift)

1. 什么是 CLS

CLS:从页面开始加载到其生命周期状态更改为隐藏期间发生的所有意外布局偏移的累计得分。

每当可见元素的位置从渲染的帧更改为下一帧时,都会发生布局偏移。

1.1. 什么是布局偏移

布局偏移由 Layout Instability API 定义。

只要窗口内可见的元素在两帧之间更改起始位置,该 API 就会报告 layout-shift 。此类元素被视为不稳定元素。

image

1.2. CLS

当资源以异步方式加载或 DOM 元素被动态添加到页面的现有内容之前,页面内容通常会发生意外移动。

布局偏移的原因可能包括尺寸未知的图片或视频、呈现的字体大于或小于其初始后备值,或者第三方广告或微件会自行调整大小。

由于网站在开发过程中的运行情况与其用户的体验之间的差异,会使此问题变得更糟。例如:

  • 个性化内容或第三方内容在开发和生产环境中的行为通常有所不同。

  • 测试图片通常已存在于开发者的浏览器缓存中,但为最终用户加载所需时间更长。

  • 在本地运行的 API 调用速度通常非常快,以至于开发过程中出现明显的延迟,在生产环境中可能就会出现严重的延迟。

2. 页面生命周期

image

3. 良好的 CLS 是多少?

为了提供良好的用户体验,网站应努力使 CLS 得分不超过 0.1

image

4. 如何衡量 CLS

5. JS 中衡量 CLS

5.1. 简单示例

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('Layout shift:', entry);
  }
}).observe({type: 'layout-shift', buffered: true});

5.2. 指标与 API 的区别

  • 如果网页是在后台加载的,或者在浏览器绘制任何内容之前在后台播放,则系统不应报告任何 CLS 值。

  • 如果某个网页从往返缓存中恢复,其 CLS 值应重置为零,因为用户此次体验是一次不同的网页访问。

  • API 不会针对 iframe 中发生的偏移报告 layout-shift ,但该指标会报告这些变化,因为它们会影响网页的用户体验。

5.3. 使用 web-vitalsJavaScript 库衡量 CLS

可以使用 web-vitalsJavaScript来衡量 CLS

import {onCLS} from 'web-vitals';

onCLS(console.log);

onCLS 源码

6. 如何改善 CLS?

  • 改善没有尺寸的图片

  • 给嵌入内容的延迟加载预留空间

  • 动画:尽量使用 transform 平移动画、缩放、旋转/倾斜元素

  • 网络字体优化

七、TTFB(Time to First Byte)

1. 什么是 TTFB?

TTFB:网络使用资源的第一个字节响应用户请求所需的时间。

TTFB 是以下请求阶段的总和:

  • 重定向时间

  • Service Worker 启动时间(如果适用)

  • DNS 查找

  • 连接和 TLS 协商

  • 请求,直到响应的第一个字节到达

缩短连接设置时间和后端的延迟时间有助于降低 TTFB

2. 良好的 TTFB 是多少时间?

大多数网站都应尽量将 TTFB 控制在 0.8 秒以内。

image

3. 如何衡量 TTFB?

4. JS 衡量 TTFB

4.1. 简单示例

new PerformanceObserver((entryList) => {
  const [pageNav] = entryList.getEntriesByType('navigation');

  console.log(`TTFB: ${pageNav.responseStart}`);
}).observe({
  type: 'navigation',
  buffered: true
});

image

4.2. 使用 web-vitalsJavaScript 库衡量 TTFB

使用 web-vitalsJavaScript也可以在浏览器中以较低的复杂性测量 TTFB

import {onTTFB} from 'web-vitals';

onTTFB(console.log);

onTTFB 源码

5. 如何优化 TTFB?

  • 具体的项目平台

  • 托管服务商

  • CDN

  • 尽可能的使用缓存

  • 避免多次重定向

  • 使用 service worker

八、FID(First Input Delay)

1. 什么是 FID?

FID:从用户首次与网页互动到浏览器实际能够开始处理事件处理脚本以响应相应互动的时间。

2. 良好的 FID 是多少时间?

为了提供良好的用户体验,网站应努力将 FID 控制在 100 毫秒以内

image

3. 如何衡量 FID?

FID 指标只能在实际操作衡量,因为它需要真实用户的网页互动

  • Chrome 用户体验报告

  • PageSpeed Insights

  • web-vitals JavaScript

  • PerformanceObserver

4. 衡量 JS 中的 FID

4.1. 简单示例

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    const delay = entry.processingStart - entry.startTime;
    console.log('FID candidate:', delay, entry);
  }
}).observe({type: 'first-input', buffered: true});

image

4.2. 使用 web-vitals JavaScript 库来衡量 FID

import {onFID} from 'web-vitals';

onFID(console.log);

onFID 源码

5. 如何优化 FID?

  • 拆分长任务

  • 使用 web worker

  • 缩短 JS 执行时间

  • 减少多余的 JS

  • 针对具体的情况优化页面

九、总结

  • 本文整体的概括了以用户为中心的性能衡量指标
  • 也对每个指标进行了具体的描述和提出优化方案
  • 希望对大家有帮助

参考