核心页面指标 (Core Web Vitals) —— LCP、INP、CLS

69 阅读13分钟

核心网页指标是适用于所有网页的一部分网页指标,所有网站所有者都应衡量这些指标,并且这些指标将显示在所有 Google 工具中。核心网页指标中的每个指标分别代表着用户体验的不同方面,可在实际环境中衡量,并反映了以用户为中心的关键结果的真实体验。

Largest Contentful Paint (LCP) 最大内容渲染时间

Largest Contentful Paint (LCP) 是一项稳定且重要的 Core Web Vitals 指标,用于衡量用户感知的加载速度,因为它会将网页主要内容可能已加载的时间点标记在网页加载时间轴中。LCP 越快,有助于让用户确信网页有用

LCP 会报告视口内可见的最大图片、文本块或视频的渲染时间(相对于用户首次导航到网页的时间)。

LCP 得分多少算好?

LCP 值在 2.5 秒或更短时间内为良好,大于 4.0 秒为较差,介于两者之间的值则需要改进

LCP 值在 2.5 秒或更短时间内为良好,大于 4.0 秒为较差,介于两者之间的值则需要改进

会考虑哪些元素?

  • <img> 元素(第一帧呈现时间适用于 GIF 或动画 PNG 等动画内容)
  • <svg> 元素中的 <image> 元素
  • <video> 元素(使用海报图片加载时间或视频的第一帧呈现时间,以较早者为准)
  • 使用 url() 函数加载背景图片的元素(而不是 CSS 渐变
  • 包含文本节点或其他内嵌级文本元素子元素的块级元素。

获取方式

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

或者

import {onLCP} from 'web-vitals';

// Measure and log LCP as soon as it's available.
onLCP(console.log);

优化LCP

LCP 子部分LCP 占比 (%)
加载第一个字节所需时间~40%
资源加载延迟<10%
资源加载时长~40%
元素渲染延迟<10%
总计100%

概括来讲,优化 LCP 可分为以下四个步骤:

  1. 确保 LCP 资源尽早开始加载。
  2. 确保 LCP 元素可在其资源完成加载后立即渲染。
  3. 在不牺牲质量的情况下,尽可能缩短 LCP 资源的加载时间。
  4. 尽快提供初始 HTML 文档。

消除资源加载延迟

  • LCP 元素需要 CSS 背景图片,但该图片是在 HTML 标记中使用 <link rel="preload">(或使用 Link 标头)预加载的。
  • LCP 元素是一个文本节点,需要 Web 字体才能呈现,并且该字体是在 HTML 标记中使用 <link rel="preload">(或使用 Link 标头)加载的。
预连接关键域名
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="dns-prefetch" href="https://cdn.example.com">

预加载关键字体
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

预加载 LCP 图片
<link rel="preload" href="hero-image.webp" as="image" fetchpriority="high">
  • LCP 元素是 <img> 元素,其 src 或 srcset 属性存在于初始 HTML 标记中。
  • 如果您认为 <img> 元素可能是网页的 LCP 元素,不妨为其设置 fetchpriority="high"
<img fetchpriority="high" src="/path/to/hero-image.webp">

消除元素渲染延迟

  • 移除未使用的 CSS:使用 Chrome 开发者工具查找未使用的 CSS 规则,并确定是否可以将其移除(或推迟)。
  • 推迟非关键 CSS:将样式表拆分为初始网页加载所需的样式,以及可以延迟加载的样式。
  • 缩减和压缩 CSS:对于重要的样式,请确保尽可能缩减其传输大小
  • 延迟或内嵌会阻止渲染的 JavaScript
  • 使用服务器端呈现

缩短资源加载时长

缩短加载第一个字节所需时间

  • 使用浏览器缓存
  • 避免多次重定向
  • 使用CDN
  • 流式传递文件

Interaction to Next Paint (INP) 交互到下次绘制的时间/下一次绘制时间

Interaction to Next Paint (INP) 是一项稳定的 Core Web Vitals 指标,用于使用 Event Timing API 中的数据评估响应速度。INP 会观察用户与网页进行的所有互动的延迟时间,并报告所有(或几乎所有)互动所低于的单个值。INP 值越低,表示网页对所有或绝大多数用户互动都能始终快速响应。

用户点击按钮 → 浏览器处理事件 → 屏幕更新画面
          │___________________│
                 INP 时长

INP 得分怎样才算理想?

  • INP 低于或等于 200 毫秒表示网页响应速度良好
  • 如果 INP 高于 200 毫秒,但低于或等于 500 毫秒,则表示网页的响应能力需要改进
  • INP 超过 500 毫秒表示网页响应缓慢

inp-desktop-v2.svg

仅会观察以下互动类型

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

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

INP 是 First Input Delay (FID) 的后继指标。虽然这两者都是响应速度指标,但 FID 仅衡量网页上首次互动的输入延迟。INP 通过观察网页上的所有互动(从输入延迟开始,到运行事件处理脚本所需的时间,最后到浏览器绘制下一个帧为止)来改进 FID。

这些差异意味着 INP 和 FID 是不同类型的响应能力指标。FID 是一种加载响应能力指标,旨在评估网页给用户的第一印象;而 INP 是一种更可靠的总体响应能力指标,无论网页互动发生在网页生命周期的什么时间点,它都能反映网页的总体响应能力。

快问快答

  • INP 指标的主要目标是什么? - 尽可能缩短用户发起互动到下一个帧绘制完成所需的时间,适用于用户发起的所有或大多数互动。
  • 如何为 INP 定义互动“延迟时间”? - 从互动开始到下一个帧完全呈现所用的时间。
  • INP 和 FID 有何区别? - INP 会考虑所有互动的完整时长,而 FID 仅衡量首次互动的输入延迟时间。

优化

输入延迟时间:从用户发起与网页的互动开始,到互动事件回调开始运行结束。

输入延迟是指从用户首次与网页互动(例如点按屏幕、用鼠标点击或按键)到该互动对应的事件回调开始运行之间的时间段。每次互动都会先有一段输入延迟。

a-simplified-visualizatio-d1514b424d9ec_1920.png

避免使用会触发过多主线程工作的周期性计时器

JavaScript 中有两个常用的计时器函数可能会导致输入延迟:setTimeout 和 setInterval;

  • setTimeout 本身没有问题,事实上,它有助于避免执行长时间的任务。不过,具体取决于超时发生的时间,以及用户在超时回调运行时是否尝试与页面互动。;
  • setInterval 会按间隔运行回调,因此更有可能妨碍互动。这是因为,与 setTimeout 调用的单个实例不同(这是一个一次性回调,可能会妨碍用户互动),setInterval 的周期性性质使其更有可能妨碍互动,从而增加互动的输入延迟。
避免长任务

什么是任务?- 任务是指浏览器执行的任何单独工作。这些工作包括呈现、解析 HTML 和 CSS、运行 JavaScript 以及您可能无法直接控制的其他类型的工作。

什么是主线程?- 主线程是浏览器中运行大多数任务的地方,主线程一次只能处理一个任务。任何用时超过 50 毫秒的任务都是长任务。对于超过 50 毫秒的任务,任务的总时间减去 50 毫秒称为任务的阻塞时段

长任务拆分

// 优化前
function processData() { /* 耗时 120ms */ }

// 优化后
function chunkedProcess() {
  const chunks = splitData(); // 数据分块
  let i = 0;
  function processChunk() {
    if (i >= chunks.length) return;
    process(chunks[i++]);
    queueMicrotask(processChunk); // 分块执行
  }
  processChunk();
}
注意互动重叠

互动重叠是指在与某个元素互动后,您在初始互动有机会渲染下一帧之前,又与该页面进行了另一次互动。

防抖,节流 函数

优化事件回调

经常让出主线程
function sendAnalyticsData() { /* ... */ }

// 主线程空闲时执行
if ('requestIdleCallback' in window) {
  requestIdleCallback(sendAnalyticsData);
} else {
  setTimeout(sendAnalyticsData, 0);
}
避免布局抖动

布局抖动(有时称为强制同步布局)是一种渲染性能问题,其中布局是同步进行的。当您在 JavaScript 中更新样式,然后在同一任务中读取它们时,就会发生布局抖动。

分离读取和写入操作:

// 错误写法(触发多次重排)
element.style.width = '100px';
const width = element.offsetWidth;
element.style.height = `${width * 2}px`;

// 正确写法(读写分离)
const width = element.offsetWidth; // 批量读
requestAnimationFrame(() => {      // 批量写
  element.style.width = '100px';
  element.style.height = `${width * 2}px`;
});

最大限度缩短呈现延迟时间

尽量减小 DOM 大小

某些情况下,无法大幅缩减大型 DOM。虽然您可以采取一些方法来缩减 DOM 大小,例如扁平化 DOM 或在用户互动期间添加到 DOM 以保持初始 DOM 大小较小,但这些方法可能只能起到一定的作用。

  1. 在初始页面呈现期间,大型 DOM 需要执行大量工作才能呈现页面的初始状态。
  2. 在响应用户互动时,大型 DOM 可能会导致渲染更新非常耗费资源,从而增加浏览器呈现下一帧所需的时间。
使用 content-visibility 延迟渲染屏幕外元素

Cumulative Layout Shift (CLS) 累积布局偏移

Cumulative Layout Shift (CLS) 是一项稳定的 Core Web Vitals 指标。这是一个以用户为中心的重要指标,用于衡量视觉稳定性,因为它有助于量化用户遇到意外布局偏移的频率。CLS 较低有助于确保网页令人愉悦

意外的布局偏移可能会以多种方式干扰用户体验,例如,如果文本突然移动,会导致用户在阅读时迷失位置,或者导致用户点击错误的链接或按钮。

什么是 CLS?

CLS 用于衡量在网页的整个生命周期内发生的每一次意外布局偏移的布局偏移得分的最高累计分数。

CLS 得分怎样才算理想?

为了提供良好的用户体验,网站应尽力使 CLS 得分不高于 0.1。为确保大多数用户都能达到此目标值,一个合适的衡量阈值是网页加载时间的第 75 个百分位数,并按移动设备和桌面设备进行细分。

good-cls-values.svg

布局偏移详解 - 布局偏移分数

CLS分数 = 距离分数 × 影响百分比

以下实例:

实例1:

影响范围比例

有一个元素在一个帧中占据了视口的一半 -> 在下一个画面中,该元素向下移动视口高度的 25%。红色虚线矩形表示元素在两个帧中的可见区域的并集,在本例中,该区域占整个视口的 75%,因此其影响百分比为 0.75

impact-fraction-example-164341c82ee76_1920.png

位移距离比例

在前面的示例中,视口的最大尺寸是高度,并且不稳定的元素移动了视口高度的 25%,因此距离分数为 0.25。

distance-fraction-example-9146d2a862482_1920.png

最后分数:

影响分数为 0.75距离分数为 0.25,因此布局偏移得分为 0.75 * 0.25 = 0.1875

实例2:向现有元素添加内容如何影响布局偏移得分

layout-shift-example-mul-10d90b67b5d6a_1920.png

在此示例中,灰色方框会更改大小,但其起始位置不会更改,因此它不是不稳定的元素

“点击我!”按钮之前不在 DOM 中,因此其起始位置也不会发生变化

绿色方框的起始位置确实会发生变化,但由于它已部分移出视口,因此在计算影响百分比时不会考虑不可见区域。两个帧中绿色框的可见区域(以红色虚线矩形表示)的并集与第一个帧中的绿色框的区域相同,即视口的 50%。影响分数为 0.5

距离分数用紫色箭头表示。绿色方框向下移动了视口大约 14%,因此距离分数为 0.14

布局偏移分数为 0.5 x 0.14 = 0.07

实例3:多个不稳定元素如何影响网页的布局偏移得分

layout-shift-example-sta-05cf93597fcee_1920.png

显示了针对动物的 API 请求的四个结果,这些结果按字母顺序排序。在第二个画面中,系统会向已排序的列表中添加更多结果。

列表中的第一项(“猫”)在帧之间不会更改其起始位置,因此是稳定的。同样,添加到列表的新项之前不在 DOM 中,因此它们的起始位置也不会发生变化。但是,标记为“狗”“马”和“斑马”的项都将其起始位置移到了其他位置,因此它们是不稳定的元素

同样,红色虚线矩形表示这三个不稳定元素的“前”和“后”区域的并集,在本例中,这大约占视口区域的 60%(0.60 的影响分数)。

箭头表示不稳定元素从其起始位置移动的距离。“斑马线”元素(由蓝色箭头表示)移动了最多,移动了约视口高度的 30%。因此,在此示例中,距离分数为 0.3

布局偏移分数为 0.60 x 0.3 = 0.18

获取方式

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

onCLS(console.log);

优化

导致 CLS 较低的最常见原因包括:

  • 没有尺寸的图片。
  • 没有尺寸的广告、嵌入内容和 iframe。
  • 动态注入的内容,例如不含维度的广告、嵌入内容和 iframe。
  • 网页字体。

未指定尺寸的图片

为媒体元素设置尺寸属性 避免图片/视频加载后挤压下方内容

<!-- 指定 width 和 height -->
<img src="转存失败,建议直接上传图片文件 banner.jpg" width="600" height="400" alt="Banner转存失败,建议直接上传图片文件">
<!-- 或通过 CSS 固定宽高比容器 -->
<div class="img-container" style="aspect-ratio: 16/9;"></div>

广告、嵌入内容和其他延迟加载的内容

  1. 为延迟加载的内容预留空间
    • 添加 min-height CSS 规则来预留空间
    • 使用 aspect-ratio CSS 属性
  2. 将延迟加载的内容放置在视口的下方
  3. 避免在没有用户互动的情况下插入新内容

动画

使用 transform 动画来平移、缩放、旋转或倾斜元素。使用 translate 的合成动画无法影响其他元素,因此不会计入 CLS。未合成的动画也不会导致重新布局。

如需详细了解哪些 CSS 属性会触发布局偏移,请参阅高性能动画

网页字体

  • font-display: optional 可以避免重新布局,因为只有在初始布局时可用时,才会使用 Web 字体。
  • 确保使用适当的后备字体。例如,使用 font-family: "Google Sans", sans-serif; 可确保在加载 "Google Sans" 时使用浏览器的 sans-serif 后备字体。如果仅使用 font-family: "Google Sans" 而不指定回退字体,则表示系统会使用默认字体,在 Chrome 中,默认字体是“Times”字体,这是一种衬线字体,比默认的 sans-serif 字体更不匹配。
  • 使用新的 size-adjustascent-overridedescent-override 和 line-gap-override API 最大限度地减少后备字体与 Web 字体之间的大小差异,如改进后的字体后备一文中所详述。
  • Font Loading API 可以缩短获取必要字体所需的时间。
  • 使用 <link rel=preload> 尽早加载重要的 Web 字体。预加载的字体更有可能满足首次绘制条件,在这种情况下,不会发生布局偏移。
<link rel="preload" href="font.woff2" as="font" crossorigin>

详细文档