Cumulative Layout Shift (CLS)

Milica Mihajlija
Milica Mihajlija

浏览器支持

  • 77
  • 79
  • x
  • x

来源

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

意外的布局偏移可能会在很多方面干扰用户体验,包括在文本突然移动导致用户在阅读时丢失位置,以及让用户点击错误的链接或按钮。在某些情况下,这可能会造成严重损害。

布局的突然偏移会导致用户确认他们本打算取消的大订单。

如果资源以异步方式加载,或 DOM 元素被动态添加到网页中的现有内容之前,通常会发生网页内容意外移动的情况。导致移动的原因可能是:尺寸未知的图片或视频、呈现的字体大于或小于其后备广告的尺寸,或者第三方广告或 widget 会自行调整自身大小。

网站在开发过程中的运行方式与其用户的体验之间的差异会导致此问题变得更加严重。例如:

  • 个性化内容或第三方内容在开发和生产环境中的行为通常有所不同。
  • 测试图片通常已存在于开发者的浏览器缓存中,但为最终用户加载所需时间更长。
  • 在本地运行的 API 调用速度通常非常快,以至于开发过程中会出现明显的延迟。

Cumulative Layout Shift (CLS) 指标可衡量真实用户发生这种情况的频率,可帮助您解决此问题。

什么是 CLS?

CLS 衡量的是网页生命周期内发生的每次意外布局偏移的最大布局偏移得分

只要可见元素的位置从一个渲染的帧更改为下一个渲染帧,就会发生布局偏移。如需详细了解如何衡量这些偏移,请参阅布局偏移得分

一次或多次布局偏移(称为会话时段)是指快速连续发生一个或多个布局偏移,且每次偏移之间的间隔不超过 1 秒,最长为 5 秒。

最大的突发时间是会话窗口,该窗口内所有布局偏移的最高累计得分。

会话窗口示例。蓝条表示每次布局偏移的得分。

良好的 CLS 得分是什么?

为了提供良好的用户体验,网站的 CLS 得分必须不超过 0.1。为确保大多数用户都能达到此目标,我们建议衡量网页加载的第 75 个百分位(按移动设备和桌面设备细分)。

良好 CLS 值不超过 0.1,较差值大于 0.25,并且介于两者之间的任何值都需要改进
良好的 CLS 值不超过 0.1。不良值大于 0.25。

如需详细了解此建议背后的研究和方法,请参阅定义核心网页指标阈值

布局偏移详情

布局偏移由 Layout Instability API 定义。只要视口内可见的元素在两帧之间更改其起始位置(例如,在默认写入模式下,该元素的顶部和左侧位置),该 API 就会报告 layout-shift 条目。起始位置发生变化的元素被视为不稳定元素

仅当现有元素更改其起始位置时,才会发生布局偏移。如果向 DOM 添加新元素或某个现有元素更改了尺寸,那么只有当此类更改导致其他可见元素更改其起始位置时,系统才会计为布局偏移。

布局偏移得分

为了计算布局偏移得分,浏览器会考虑视口大小,以及视口中不稳定元素在两个渲染帧之间的移动。布局偏移分数是该移动的两种度量的乘积:影响分数和距离分数。

layout shift score = impact fraction * distance fraction

影响比例

影响比例衡量的是不稳定的元素如何影响两个帧之间的视口区域。

给定帧的影响比例是该帧和前一帧所有不稳定元素的可见区域组合(占视口总面积的比例)。

含有一个不稳定元素的冲击比例示例
如果某个元素的位置发生变化,其前一个和当前位置都会影响到该元素的影响比例。

此图片显示的元素占据了一帧中的一半视口。在下一帧中,该元素会向下移动 25% 的视口高度。红色虚线矩形表示元素在两个帧上的可见区域,在本例中占总视口的 75%,因此其影响比例为 0.75

距离分数

布局偏移得分公式的另一部分用于测量不稳定元素相对于视口移动的距离。距离比例是任意不稳定元素在帧中移动的最大水平或垂直距离除以视口的最大尺寸(宽度或高度,以较大者为准)。

带有一个不稳定元素的距离分数示例
距离比例用于衡量元素在视口中移动了多远。

在本例中,最大的视口尺寸是高度,不稳定元素移动了视口高度的 25%,因此距离比例为 0.25

如果影响比例为 0.75,距离比例为 0.25,则布局偏移得分为 0.75 * 0.25 = 0.1875

示例

接下来的示例说明了向现有元素添加内容对布局偏移得分的影响:

具有多个稳定元素和_不稳定元素_的布局偏移示例
在灰色框底部添加一个按钮会将绿色框向下推动部分移出视口。

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

“Click Me!”按钮之前不在 DOM 中,因此其起始位置也没有改变。

绿色框的起始位置确实会发生变化,但已部分移出视口,因此在计算影响比例时不考虑不可见区域。两个帧中绿色框的可见区域(红色虚线矩形)的并集等于第一帧中绿色框的面积(占视口的 50%)。影响比例为 0.5

距离比例用蓝色箭头表示。绿色框已向下移动了大约 14% 的视口,因此距离比例为 0.14

布局偏移的得分为 0.5 x 0.14 = 0.07

以下示例展示了多个不稳定的元素如何影响页面的布局偏移得分:

包含“稳定”和“不稳定的元素”以及视口裁剪的布局偏移示例
随着此排序列表中出现更多名称,现有名称将移动以保持字母顺序。

列表中的第一项(“Cat”)不会改变其在不同帧之间的起始位置,因此是稳定的。添加到列表中的新项之前不在 DOM 中,因此它们的起始位置也没有改变。但是,标有“狗”“马”和“斑马”的项都会改变其起始位置,因此这些元素是不稳定的。

同样,红色虚线矩形表示这三个不稳定元素在偏移前后的面积,在本例中,大约为视口区域的 60%(影响比例为 0.60)。

箭头表示不稳定元素从起始位置移动的距离。以蓝色箭头表示的“斑马”元素移动幅度最大,移动了视口高度的 30% 左右。这会使此示例中的距离比例变为 0.3

布局偏移的得分为 0.60 x 0.3 = 0.18

预期与意外的布局偏移

并非所有布局偏移都是有害的。事实上,许多动态 Web 应用会经常改变页面上元素的初始位置。只有在用户没有预料到时,布局偏移才是不良行为。

用户发起的布局偏移

通常,为了响应用户互动(例如点击或点按链接、按下按钮或在搜索框中输入)而发生的布局偏移是可以接受的,只要发生的位置距离互动足够接近且用户能够清楚了解两者之间的关系即可。

例如,如果用户交互触发了可能需要一段时间才能完成的网络请求,则最好立即创建一些空间并显示加载指示器,以避免请求完成时导致令人不适的布局偏移。如果用户没有意识到正在加载内容,或者不知道资源何时准备就绪,他们可能会在等待时尝试点击其他内容,当第一个元素完成加载时,该其他元素可能会从其下方移出。

对于在用户输入后 500 毫秒内发生的布局偏移,系统会设置 hadRecentInput 标志,因此您可以将其从计算中排除。

动画和过渡

如果设计得当,动画和过渡效果是更新网页内容的绝佳方式,而且不会让用户感到意外。如果网页上的内容突然发生变化,则几乎总是会造成糟糕的用户体验。但是,内容从一个位置自然地逐步移动到另一个位置通常有助于用户更好地了解正在发生的情况,并引导用户完成状态变化。

请务必遵循 prefers-reduced-motion 浏览器设置,因为动画可能会给某些网站访问者带来健康或注意力问题。

借助 CSS transform 属性,您可以为元素添加动画效果,而不会触发布局偏移:

  • 使用 transform: scale(),而不是更改 heightwidth 属性。
  • 如需移动元素,请使用 transform: translate(),而不要更改 toprightbottomleft 属性。

如何衡量 CLS

CLS 可以在实验室现场测量,并且在以下工具中提供。

野外工具

实验工具

测量 JavaScript 中的布局偏移

如需测量 JavaScript 中的布局偏移,请使用 Layout Instability API

以下示例展示了如何创建 PerformanceObserver 以将 layout-shift 条目记录到控制台:

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

在 JavaScript 中衡量 CLS

如需在 JavaScript 中衡量 CLS,请将意外登录的会话的 layout-shift 条目进行分组,并计算最大会话价值。如需查看参考实现,请参阅 web vitals JavaScript 库源代码

在大多数情况下,卸载页面时的 CLS 值是该页面的最终 CLS 值,但也有一些重要的例外情况,请参阅下一部分。web vitals JavaScript 库会在 Web API 的限制范围内尽可能多地考虑这些因素。

指标与 API 的区别

  • 如果网页在后台加载,或者在浏览器绘制任何内容之前在后台运行,则不应报告任何 CLS 值。
  • 如果从返回或转发缓存中恢复某个页面,其 CLS 值应重置为零,因为用户这是一次不同的页面访问。
  • 该 API 不会针对 iframe 中发生的偏移报告 layout-shift 条目,但该指标会报告,因为这些条目会影响网页的用户体验。这可能会表现为 CrUX 和 RUM 之间的差异。为了正确衡量 CLS,您必须添加 iframe。子帧可以使用该 API 将其 layout-shift 条目报告给父帧以进行聚合

除了这些异常之外,CLS 更为复杂,因为它会衡量页面的整个生命周期:

  • 用户可能会长时间(几天、几周,甚至几个月)保持打开标签页。 事实上,用户可能永远不会关闭标签页。
  • 在移动操作系统上,浏览器通常不会针对后台标签页运行页面卸载回调,因此很难报告“最终”值。

为了处理此类情况,我们建议,您的系统除了会在网页处于后台加载时报告 CLS,还应在网页加载时报告 CLS。这两种场景都受 visibilitychange 事件的约束。然后,接收此数据的分析系统需要在后端计算最终 CLS 值。

开发者可以使用 web-vitals JavaScript 库来衡量 CLS,该库考虑了此处提到的所有内容(iframe 情况除外),而无需自行记忆和处理所有这些情况:

import {onCLS} from 'web-vitals';

// Measure and log CLS in all situations
// where it needs to be reported.
onCLS(console.log);

如何改善 CLS

如需有关识别现场布局偏移以及利用实验室数据进行优化的更多指导,请参阅优化 CLS 指南。

其他资源

更新日志

有时,bug 会在用于衡量指标的 API 中发现,有时会在指标本身的定义中发现。因此,有时必须进行更改,这些更改可能会在内部报告和信息中心内显示为改进或回归。

为了帮助您管理这一点,变更日志中列出了对这些指标的实现或定义的所有更改。

如果您对这些指标有反馈意见,请在 web-vitals-feedback Google 网上论坛中提供。