Cumulative Layout Shift (CLS)

Milica Mihajlija
Milica Mihajlija

浏览器支持

  • 77
  • 79
  • x
  • x

来源

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

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

当资源以异步方式加载或 DOM 元素被动态添加到页面的现有内容之前,页面内容通常会发生意外移动。布局偏移的原因可能包括尺寸未知的图片或视频、呈现的字体大于或小于其初始后备值,或者第三方广告或微件会自行调整大小。

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

  • 个性化内容或第三方内容在开发和生产环境中的行为通常有所不同。
  • 测试图片通常已存在于开发者的浏览器缓存中,但为最终用户加载所需时间更长。
  • 在本地运行的 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

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

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

在上图的第一帧中,包含动物的 API 请求有四条结果,按字母顺序排序。在第二帧中,更多结果被添加到已排序的列表。

列表中的第一项(“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 属性。
  • 如需移动元素,请避免更改 toprightbottomleft 属性,并改用 transform: translate()

如何衡量 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 值是该网页的最终 CLS 值,但也有一些重要的例外情况,详见下一部分。在 Web API 的限制范围内,web vitals JavaScript 库会尽可能考虑这些因素。

指标与 API 的区别

  • 如果网页是在后台加载的,或者在浏览器绘制任何内容之前在后台播放,则系统不应报告任何 CLS 值。
  • 如果某个网页从往返缓存中恢复,其 CLS 值应重置为零,因为用户此次体验是一次不同的网页访问。
  • 该 API 不会针对 iframe 中发生的偏移报告 layout-shift 条目,但该指标会报告这些变化,因为它们会影响网页的用户体验。这可能会表现为 CrUX 和 RUM 之间的差异。如要正确衡量 CLS,您应考虑 CLS。子框架可以使用该 API 将其 layout-shift 条目报告给父框架以进行汇总

除了这些例外情况之外,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 网上论坛中提供。