优化 Cumulative Layout Shift

了解如何避免突发的布局偏移,以提升用户体验

Cumulative Layout Shift (CLS)核心网页指标的三个指标之一。它通过结合可见内容在视口中的偏移量与受影响元素移动的距离来衡量内容的不稳定性。

布局偏移可能会分散用户的注意力。假设您刚开始阅读一篇文章,突然网页上的元素开始在页面上移动,这会让您感到困惑,并需要您重新找到阅读位置。这种情况在网络上非常常见,包括在阅读新闻或尝试点击“搜索”或“添加到购物车”按钮时。此类体验在视觉上会令人反感且令人沮丧。当可见元素因其他元素突然被添加到页面或调整大小而被迫移动时,通常会导致此类问题。

为了提供良好的用户体验,网站应尽量确保至少 75% 的网页访问的 CLS 不高于 0.1。

良好的 CLS 值低于 0.1,不良值大于 0.25,介于 0.25 之间的值需要改进
良好的 CLS 值应为 0.1 或更低。差的值大于 0.25。

与其他 Core Web Vitals 指标(以秒或毫秒为单位的时间值)不同,CLS 得分是一个无单位值,基于计算内容偏移量和偏移距离而得出。

在本指南中,我们将介绍如何优化导致布局偏移的常见原因。

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

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

了解布局偏移的原因

在开始寻找常见 CLS 问题的解决方案之前,请务必了解您的 CLS 得分以及变化的原因。

实验室工具与现场的 CLS

我们经常听到开发者认为 Chrome 用户体验报告 (CrUX) 衡量的 CLS 不正确,因为它与他们使用 Chrome 开发者工具或其他实验室工具衡量的 CLS 不一致。Lighthouse 等网站性能实验室工具可能不会显示网页的完整 CLS,因为它们通常只会简单加载网页,以衡量一些网站性能指标并提供一些指导(不过,Lighthouse 用户体验流程确实允许您衡量超出默认网页加载审核范围的指标)。

CrUX 是 Web Vitals 计划的官方数据集,因此,CLS 是衡量网页在整个生命周期内的表现,而不仅仅是实验室工具通常衡量的初始网页加载期间的表现。

在网页加载期间,布局偏移非常常见,因为系统会提取所有必要的资源来初始呈现网页,但布局偏移也可能会在初始加载后发生。许多加载后偏移可能是用户互动的结果,因此会被排除在 CLS 得分之外,因为它们是预期的偏移(前提是它们发生在该互动后的 500 毫秒内)。

不过,如果用户没有进行符合条件的互动,系统可能会纳入用户意外看到的其他加载后偏移,例如,如果您在网页中滚动到更远的位置,系统会加载延迟加载的内容,而这会导致偏移。导致加载后 CLS 较高的一些其他常见原因与转换互动有关,例如在单页应用中,转换互动耗时超过 500 毫秒宽限期。

PageSpeed Insights 会在“了解您的真实用户体验”部分显示网址的用户感知 CLS,并在“诊断性能问题”部分显示基于实验室的加载 CLS。这两个值之间的差异可能是由于加载后 CLS 导致的。

PageSpeed Insights 屏幕截图,显示网址级数据,突出显示真实用户 CLS 远高于 Lighthouse CLS
在此示例中,CrUX 测量的 CLS 比 Lighthouse 大得多。

确定加载 CLS 问题

如果 PageSpeed Insights 的 CrUX 和 Lighthouse CLS 得分大致一致,这通常表示 Lighthouse 检测到有加载 CLS 问题。在这种情况下,Lighthouse 会帮助您执行两项审核,以便提供有关因缺少宽度和高度而导致 CLS 的图片的更多信息,还会列出网页加载时发生偏移的所有元素及其对 CLS 的影响。您可以通过过滤 CLS 审核来查看这些审核:

Lighthouse 屏幕截图:显示 CLS 审核结果,提供更多信息来帮助您发现和解决 CLS 问题
Lighthouse 的详细 CLS 诊断。

DevTools 中的“性能”面板还会在体验部分突出显示布局偏移。Layout Shift 记录的摘要视图包含累计布局偏移得分,以及显示受影响区域的矩形叠加层。这对于详细了解加载 CLS 问题特别有用,因为这类问题可以通过重新加载性能配置文件轻松重现。

展开“体验”部分后,Chrome 开发者工具性能面板中显示的布局偏移记录
在“性能”面板中记录新的轨迹后,结果的体验部分会填充一个带有 Layout Shift 记录的红色条。点击相应记录后,系统会显示“从”和“移至”条目等详细信息,以便您深入了解受影响的元素。如图所示。

找出加载后 CLS 问题

CrUX 和 Lighthouse CLS 得分不一致通常表示有加载后 CLS 问题。如果没有实地数据,很难跟踪这些变化。如需了解如何收集字段数据,请参阅衡量字段中的 CLS 元素

在与网页互动时,您可以使用 Web Vitals Chrome 扩展程序在信息即时显示 (HUD) 或控制台中监控 CLS,在控制台中,您可以在元素发生偏移时获取更多详细信息

作为使用此扩展程序的替代方案,您可以浏览网页,同时使用粘贴到控制台的性能观察器记录布局偏移

设置班次监控后,您可以尝试重现任何加载后 CLS 问题。CLS 通常发生在用户滚动浏览网页时,延迟加载的内容会完全加载,但没有为其预留空间。当用户将指针悬停在内容上时,内容发生位移是导致加载后 CLS 较高的一个常见原因。在这两种互动期间发生的任何内容转换都属于意外转换,即使发生在 500 毫秒内也是如此。

如需了解详情,请参阅调试布局偏移

找出导致 CLS 的常见原因后,您还可以使用 Lighthouse 的“时段用户体验历程”模式,确保典型用户体验历程不会因引入布局偏移而出现回归。

测量字段中的 CLS 元素

在确定 CLS 发生的情况和缩小可能原因的范围时,在现场监控 CLS 非常有用。与大多数实验室工具一样,现场工具仅测量发生偏移的元素,但通常会提供足够的信息来确定原因。您还可以使用 CLS 字段测量功能来确定哪些问题具有最高优先级的解决方式。

web-vitals 库具有归因函数,可让您收集这些额外的信息。如需了解详情,请参阅在现场调试性能。其他 RUM 提供商也已开始以类似的方式收集和呈现此类数据。

导致 CLS 较高的一些常见原因

确定导致 CLS 的原因后,您就可以着手解决问题了。在本部分中,我们将介绍导致 CLS 的一些常见原因,以及您可以采取哪些措施来避免出现这些问题。

未指定尺寸的图片

请务必为图片和视频元素添加 widthheight 尺寸属性。或者,通过 CSS aspect-ratio 或类似工具预留所需的空间。这种方法可确保浏览器在图片加载时能够在文档中分配正确数量的空间。

未指定宽度和高度的图片。
指定了宽度和高度的图片。
Lighthouse 报告,显示在为图片设置尺寸后累计布局偏移的变化情况
在 Lighthouse 6.0 中设置图片尺寸对 CLS 的影响。

图像上的 widthheight 属性的历史记录

在 Web 的早期,开发者会向 <img> 标记添加 widthheight 属性,以确保在浏览器开始提取图片之前,在页面上分配足够的空间。这样可以最大限度地减少重新流布局和重新布局。

<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

在此示例中,widthheight 不包含单位。这些“像素”尺寸可确保浏览器在网页布局中预留 640x360 区域。无论实际尺寸是否与此空间相符,图片都会拉伸以适应此空间。

自适应网页设计引入后,开发者开始省略 widthheight,改用 CSS 调整图片大小:

img {
  width: 100%; /* or max-width: 100%; */
  height: auto;
}

但是,由于未指定图片大小,因此在浏览器开始下载图片并确定其尺寸之前,无法为其分配空间。图片加载时,文本会在网页上下移以便为它们腾出空间,从而造成令人困惑和令人沮丧的用户体验。

这时,宽高比就派上用场了。图片的宽高比是其宽度与高度的比率。通常,宽高比以冒号分隔的两个数字表示(例如 16:9 或 4:3)。对于 x:y 宽高比,图片的宽度为 x 单位,高度为 y 单位。

这意味着,如果我们知道其中一个尺寸,就可以确定另一个尺寸。对于 16:9 宽高比:

  • 如果 puppy.jpg 的高度为 360 像素,则宽度为 360 x (16 / 9) = 640 像素
  • 如果 puppy.jpg 的宽度为 640 像素,则高度为 640 x (9 / 16) = 360 像素

知道图片的宽高比后,浏览器便可计算并预留足够的空间来容纳高度和相关区域。

设置图片尺寸的现代最佳实践

由于现代浏览器会根据图片的 widthheight 属性设置图片的默认宽高比,因此您可以通过为图片设置这些属性并在样式表中添加上述 CSS 来防止布局偏移。

<!-- set a 640:360 i.e a 16:9 aspect ratio -->
<img src="puppy.jpg" width="640" height="360" alt="Puppy with balloons">

然后,所有浏览器都会根据元素的现有 widthheight 属性添加默认宽高比

此函数可根据图片加载前的 widthheight 属性计算宽高比。它会在开始计算布局时提供此信息。一旦指定图片的宽度(例如 width: 100%),系统就会使用宽高比来计算高度。

aspect-ratio 值由主要浏览器在处理 HTML 时计算得出,而不是使用默认的用户代理样式表(如需深入了解原因,请参阅这篇文章),因此显示的值略有不同。例如,Chrome 在“元素”面板的“样式”部分中显示的内容会如下所示:

img[Attributes Style] {
  aspect-ratio: auto 640 / 360;
}

Safari 的行为也类似,使用 HTML 属性样式来源。Firefox 不会在其检查器面板中显示此计算的 aspect-ratio,但会将其用于布局。

前面代码中的 auto 部分非常重要,因为它会导致图片下载后图片尺寸替换默认宽高比。如果图片尺寸不同,这仍然会导致图片加载后布局发生一定程度的偏移,但这样可以确保图片宽高比在可用时仍然可用,以防 HTML 不正确。对于未提供尺寸的图片,即使实际宽高比与默认值不同,它仍然会导致布局偏移少于默认大小的 0x0。

如需深入了解宽高比并进一步思考响应式图片,请参阅使用媒体宽高比实现流畅的页面加载

如果您的图片位于容器中,您可以使用 CSS 将图片的大小调整为容器的宽度。我们设置 height: auto; 是为了避免为图片高度使用固定值。

img {
  height: auto;
  width: 100%;
}

自适应图片怎么样?

使用自适应图片时,srcset 用于定义您允许浏览器选择的图片以及每张图片的尺寸。为确保能够设置 <img> 宽度和高度属性,每张图片都应使用相同的宽高比。

<img
  width="1000"
  height="1000"
  src="puppy-1000.jpg"
  srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w"
  alt="Puppy with balloons"
/>

图片的宽高比也可能会因艺术指导而异。例如,您可能希望为窄视口提供图片的剪裁截图,并在桌面设备上显示完整图片:

<picture>
  <source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" />
  <source media="(min-width: 800px)" srcset="puppy-800w.jpg" />
  <img src="puppy-800w.jpg" alt="Puppy with balloons" />
</picture>

Chrome、Firefox 和 Safari 现在支持在给定 <picture> 元素内的 <source> 元素上设置 widthheight

<picture>
  <source media="(max-width: 799px)" srcset="puppy-480w-cropped.jpg" width="480" height="400" />
  <source media="(min-width: 800px)" srcset="puppy-800w.jpg" width="800" height="400" />
  <img src="puppy-800w.jpg" alt="Puppy with balloons" width="800" height="400" />
</picture>

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

图片并非唯一可能导致布局偏移的内容类型。广告、嵌入内容、iframe 和其他动态注入的内容都可能会导致显示在其后面的内容向下偏移,从而增加 CLS。

广告是导致网页布局偏移的主要原因之一。广告联盟和发布商通常支持动态广告尺寸。由于点击率更高,并且有更多广告参与竞价,因此广告尺寸可提升效果/收入。遗憾的是,这可能会导致用户体验不佳,因为广告会将您正在查看的可见内容向下推到页面底部。

借助可嵌入的微件,您可以在网页上添加可移植的 Web 内容,例如 YouTube 视频、Google 地图中的地图和社交媒体帖子。不过,这些 widget 在加载之前通常不知道其内容有多大。因此,提供嵌入的平台并不总是为其 widget 预留空间,这会导致 widget 最终加载时布局发生偏移。

处理这些问题的方法都很相似。主要区别在于您对要插入的内容的控制程度。如果该内容是由第三方(例如广告合作伙伴)插入的,您可能不知道要插入的内容的确切大小,也无法控制这些嵌入内发生的任何布局偏移。

为延迟加载的内容预留空间

在内容流中放置延迟加载的内容时,可以在初始布局中为其预留空间,以避免布局偏移。

一种方法是添加 min-height CSS 规则来预留空间,或者(对于广告等自适应内容)使用 aspect-ratio CSS 属性,方法与浏览器自动为提供尺寸的图片使用此属性的方式类似。

三部移动设备,第一部设备中只有文本内容,第二部设备中文本内容向下偏移,第三部设备中使用占位符预留空间,以防止文本内容向下偏移
为广告预留空间可以防止布局发生偏移

如果使用媒体查询,您可能需要考虑在不同设备类型上的广告或占位符尺寸的细微差异。

对于可能没有固定高度的内容(例如广告),您可能无法预留完全消除布局偏移所需的确切空间。如果投放的广告尺寸较小,发布商可以为较大的容器设置样式以避免布局偏移,也可以根据历史数据为广告展示位置选择最有可能的尺寸。这种方法的缺点是会增加页面上的空白。

您可以改为将初始大小设置为要使用的最小大小,并接受较大内容出现一定程度的偏移。与空元素的默认大小 0px 相比,使用 min-height(如前所述)可让父元素根据需要进行扩展,同时减少布局偏移的影响。

例如,在未返回任何广告时,尽量通过显示占位符来避免隐藏预留空间。移除为元素预留的空间可能会导致与插入内容一样多的 CLS。

将延迟加载的内容放置在视口的下方

与在视口中较低位置注入的内容相比,在更靠近视口顶部的位置动态注入的内容通常会导致布局偏移更大。不过,在视口中的任意位置注入内容仍会导致一些偏移。如果您无法为注入的内容预留空间,我们建议您将其放置在页面后面,以减少对 CLS 的影响。

避免在没有用户互动的情况下插入新内容

您可能遇到过布局偏移问题,这是因为当您尝试加载网站时,界面会在视口顶部或底部弹出。与广告类似,这种情况通常发生在会使网页其余内容偏移的横幅和表单中:

无预留空间的动态内容。

如果您需要显示这些类型的界面功能,请提前在视口中为其预留足够的空间(例如,使用占位符或骨架界面),以便在加载时,不会导致页面内容意外移动。或者,在适当的情况下叠加内容,确保该元素不属于文档流。有关这些类型组件的更多建议,请参阅 Cookie 通知最佳做法一文。

在某些情况下,动态添加内容是用户体验的重要组成部分。例如,向商品列表中加载更多商品或更新实时 Feed 内容时。在这些情况下,您可以通过多种方式避免意外的布局偏移:

  • 在固定大小的容器中将旧内容替换为新内容,或者使用轮播界面,并在转换后移除旧内容。请务必在过渡完成前停用所有链接和控件,以防止出现新内容时出现意外点击或点按。
  • 让用户发起新内容的加载,以免他们对这种转换感到意外(例如,使用“加载更多”或“刷新”按钮)。建议您在用户互动之前预加载内容,以便内容立即显示。请注意,在用户输入后 500 毫秒内发生的布局偏移不会计入 CLS。
  • 在屏幕外流畅加载内容,并叠加一条通知,告知用户内容已可用(例如,显示“向上滚动”按钮)。
Twitter 和 Chloé 网站上动态内容加载且未导致意外布局偏移的示例
动态内容加载且不会导致意外布局偏移的示例。左侧:Twitter 上正在加载的实时 Feed 内容。右图:Chloé 网站上的“加载更多”示例。了解 YNAP 团队如何在加载更多内容时针对 CLS 进行优化

动画

更改 CSS 属性值时,浏览器可能需要对这些更改做出响应。某些值(例如 box-shadowbox-sizing)会触发重新布局、绘制和合成。更改 topleft 属性也会导致布局偏移,即使被移动的元素位于其自己的层上也是如此。请避免使用这些属性设置动画。

可以在不触发重新布局的情况下更改其他 CSS 属性。这些操作包括使用 transform 动画来平移、缩放、旋转或倾斜元素。

使用 translate 的合成动画无法影响其他元素,因此不会计入 CLS。未合成的动画也不会导致重新布局。如需详细了解哪些 CSS 属性会触发布局偏移,请参阅高性能动画

网页字体

在下载网络字体之前,通常采用以下两种方式之一来处理下载和呈现网络字体:

  • 后备字体会与 Web 字体交换,从而导致未设置样式的文本闪烁 (FOUT)。
  • 在网页字体可用且文本变为可见之前,系统会使用后备字体显示“不可见”文本(FOIT - 不可见文本闪烁)。

这两种方法都可能会导致布局偏移。即使文本不可见,系统仍会使用回退字体对其进行排版,因此当网页字体加载时,文本块和周围内容会与可见字体一样发生偏移。

以下工具可以帮助您最大限度地减少文本偏移:

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

如需了解其他字体最佳实践,请参阅字体最佳实践

确保网页符合 bfcache 的条件,从而降低 CLS

保持较低的 CLS 得分的有效方法是确保您的网页符合往返缓存 (bfcache) 的条件。

在您离开网页后,bfcache 会将网页保留在浏览器内存中一小段时间,以便您在返回时看到与离开时完全相同的网页。也就是说,页面完全加载后会立即显示,而不会出现通常在加载过程中因之前给出的任何原因而出现的任何移位。

虽然这可能仍然意味着首次加载网页时会遇到布局偏移,但当用户返回浏览网页时,他们不会反复看到相同的布局偏移。您应始终力求避免出现偏移,即使在初始加载时也是如此。但如果完全解决此问题比较棘手,您至少可以通过避免在任何 bfcache 导航中出现偏移来减少影响。

许多网站都提供返回和前进导航功能。例如,返回到某个内容页面、某个类别页面或搜索结果。

在 Chrome 中推出此功能后,我们发现 CLS 明显得到了改善

所有浏览器都会默认使用 bfcache,但由于各种原因,有些网站不符合使用 bfcache 的条件。如需详细了解如何测试和找出阻止使用 bfcache 的任何问题,请参阅 bfcache 指南,确保您充分利用此功能来提升网站的整体 CLS 得分。

总结

如本指南前面所述,有许多方法可以识别和改进 CLS。Core Web Vitals 中内置了容许值,因此即使您无法完全消除 CLS,使用其中的一些方法应该也能减少影响。这有望让您不超出上述限制,为网站用户打造更好的体验。