优化 Cumulative Layout Shift

了解如何避免突然的布局偏移,以改善用户体验

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

布局偏移可能会分散用户的注意力。想象一下,当您开始阅读一篇文章时,页面上突然出现各种元素移动,让您感到无从下手,不得不重新找到自己的位置。这种情况在网络中很常见,包括在阅读新闻或尝试点击“搜索”时或“Add to Cart”(添加到购物车)按钮。此类体验在视觉上会令人反感且令人沮丧。这类错误通常是由于另一个元素突然添加到页面中或调整大小而强制移动可见元素导致的。

为了提供良好的用户体验,网站应努力将至少 75% 的网页访问的 CLS 控制在 0.1 或更低。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"></ph> 良好的 CLS 值低于 0.1,不良值大于 0.25,介于 0.25 之间的值需要改进
良好的 CLS 值为 0.1 或更低。不良值大于 0.25。

其他 Core Web Vitals 是基于时间的值,以秒或毫秒为单位进行衡量,而 CLS 得分则是无单位值,它通过计算内容的偏移幅度和偏移幅度计算得出。

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

CLS 不佳的最常见原因如下:

  • 图片没有尺寸。
  • 没有尺寸的广告、嵌入内容和 iframe。
  • 动态注入的内容,例如无尺寸的广告、嵌入内容和 iframe。
  • 网络字体。

了解布局偏移的原因

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

实验室工具中的 CLS 与实际运行中的 CLS

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

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

布局偏移在页面加载期间很常见,因为系统会获取最初渲染页面所需的所有资源,但布局偏移也可能发生在初始加载之后。许多加载后偏移可能由用户互动导致,因此不会计入 CLS 得分,因为它们是预期的变动,只要这些变动发生在该互动发生后的 500 毫秒内即可。

不过,在没有符合条件的互动时(例如,如果您继续滚动网页,并且系统加载了延迟加载的内容并导致了转换,则可能会导致用户意料之外的其他加载后偏移)包含在内。加载后 CLS 的其他常见原因与转换交互有关,例如在单页应用上,所需时间超过 500 毫秒的宽限期。

PageSpeed Insights可同时显示用户感知的 “发现真实用户的体验”中某个网址的 CLS部分, 以及“诊断性能问题”中基于实验室的负载 CLS部分。 这些值之间的差异可能是加载后 CLS 造成的。

<ph type="x-smartling-placeholder">
</ph> PageSpeed Insights 的屏幕截图,其中显示了网址级数据,其中突出显示了明显大于 Lighthouse CLS 的真实用户 CLS <ph type="x-smartling-placeholder">
</ph> 在此示例中,CrUX 测量的 CLS 要比 Lighthouse 大得多。
<ph type="x-smartling-placeholder">

确定加载 CLS 问题

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

<ph type="x-smartling-placeholder">
</ph> 显示 CLS 审核的 Lighthouse 屏幕截图,其中提供更多信息以帮助您识别和解决 CLS 问题 <ph type="x-smartling-placeholder">
</ph> Lighthouse 的详细 CLS 诊断。
<ph type="x-smartling-placeholder">

开发者工具中的“Performance”面板还会突出显示体验部分中的布局偏移。Layout Shift 记录的 Summary 视图包含累计布局偏移分数,以及显示受影响区域的矩形叠加层。这对于获取有关加载 CLS 问题的更多详细信息特别有用,因为可以通过重新加载性能配置文件轻松复制该问题。

<ph type="x-smartling-placeholder">
</ph> 展开“体验”部分时,Layout Shift 记录会显示在 Chrome 开发者工具性能面板中 <ph type="x-smartling-placeholder">
</ph> 在“性能”面板中记录新的轨迹后,结果的体验部分将以红色条填充,显示 Layout Shift 记录。点击该记录,即可通过显示“迁移自”等详细信息来深入了解受影响的元素“已迁移到”条目。

确定加载后 CLS 问题

CrUX 和 Lighthouse CLS 得分不一致,通常表明加载后 CLS。在没有现场数据的情况下,很难跟踪这些变化。如需了解如何收集字段数据,请参阅测量字段中的 CLS 元素

Web Vitals Chrome 扩展程序可用于在您与网页互动时(通过浮动显示窗口或控制台)监控 CLS,您可以在元素偏移上方获得更多详细信息

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

设置轮班监控后,您可以尝试重现任何加载后 CLS 问题。CLS 通常在用户滚动浏览页面时发生,那时延迟加载的内容完全加载,没有预留空间。用户将指针悬停在内容上时发生的内容偏移是加载后 CLS 的另一个常见原因。在这些互动过程中,即使发生内容在 500 毫秒内发生的所有意外变动,也视为意外发生。

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

在确定导致 CLS 的任何常见原因后,您还可以使用 Lighthouse 的时间跨度用户流模式,通过引入布局偏移来确保典型的用户流不会回归。

测量字段中的 CLS 元素

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

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

CLS 的常见原因

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

没有尺寸的图片

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

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
未指定宽度和高度的图片。
<ph type="x-smartling-placeholder">
</ph>
指定了宽度和高度的图片。
<ph type="x-smartling-placeholder">
</ph> Lighthouse 报告,显示了在图片上设置尺寸后对 Cumulative Layout Shift 的影响之前/之后的情况 <ph type="x-smartling-placeholder">
</ph> Lighthouse 6.0 对 CLS 设置图片尺寸的影响。

映像的 widthheight 属性的历史记录

在 Web 发展的早期阶段,开发者会将 widthheight 属性添加到其 <img> 标记中,以确保在浏览器开始提取图片之前,网页上有足够的空间。这样可以最大限度地减少重排和重新布局。

<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 属性,您可以通过执行以下操作来防止布局偏移: 在图片上设置这些属性,并在 样式表。

<!-- 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%),系统就会根据相应宽高比来计算高度。

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

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

Safari 采用类似的方式使用 HTML 属性样式源。Firefox 不会在 Inspector 面板中显示计算出的 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 现在支持 widthheight 给定 <picture> 元素中的 <source> 元素:

<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。

广告是导致网站布局转变的最大因素之一。广告联盟和发布商通常支持动态广告尺寸。广告尺寸可以带来更高的点击率和更多参与竞价的广告,从而提高广告效果/收入。遗憾的是,由于广告会将您正在查看的可见内容推到页面下方,这可能会导致用户体验不佳。

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

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

为延迟加载内容预留空间

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

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

<ph type="x-smartling-placeholder">
</ph> 在第三台设备中,这三台移动设备上只有文本内容,这会在第二台设备中下移,使用占位符预留空间(如第三台设备所示)可防止发生偏移 <ph type="x-smartling-placeholder">
</ph> 为广告预留空间可以防止布局偏移

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

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

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

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

将延迟加载的内容放在视口中较低的位置

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

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

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

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
动态内容没有预留空间。

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

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

  • 使用固定尺寸容器内的新内容替换旧内容,或使用轮播界面,在过渡后移除旧内容。请务必在过渡完成前停用所有链接和控件,以防止出现新内容时出现意外点击或点按。
  • 让用户开始加载新内容,这样用户就不会对这一变化感到意外(例如,使用“加载更多”或“刷新”按钮)。建议您在用户互动之前预提取内容,以便该内容能够立即显示。请注意,在用户输入后 500 毫秒内发生的布局偏移不会计入 CLS。
  • 将内容无缝加载到屏幕外,并叠加显示相应内容并告知用户(例如,使用“向上滚动”按钮)。
。 <ph type="x-smartling-placeholder">
</ph> 在不会导致 Twitter 和 Chloé 网站发生意外布局偏移的情况下加载动态内容的示例
在不导致意外布局偏移的动态内容加载示例。左图:正在 Twitter 上加载的直播信息流内容。右:“加载更多”Chloé 网站上的示例。了解 YNAP 团队如何在加载更多内容时针对 CLS 进行优化
<ph type="x-smartling-placeholder">

动画

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

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

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

网络字体

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

  • 后备字体与网页字体互换,从而引发无样式文本闪烁 (FOUT)。
  • “隐身”在有网页字体且文字变为可见(FOIT,即隐藏文字的闪烁)之前,一律以后备字体显示文字。

这两种方法都可能导致布局偏移。即使文本不可见,它仍然使用后备字体进行布局,因此在加载网页字体时,文本块和周围内容的移动方式与可见字体相同。

以下工具可以帮助您最大程度地减少文本的移位:

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

如需了解其他字体最佳做法,请参阅字体最佳做法

确保网页符合 bfcache 的使用条件,以降低 CLS

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

当您离开网页后,bfcache 会在浏览器内存中保留一小段时间,这样,当您返回这些网页时,它们就会完全恢复为您离开的网页。也就是说,页面完全加载后会立即显示,而不会出现通常在加载过程中因前面提到的任何原因而导致的偏移。

尽管这仍可能意味着初始网页加载遇到布局偏移,但当用户返回到页面时,他们并不会重复看到相同的布局偏移。您应该始终致力于避免这种变化(即使是在初始加载时),但如果完全解决这种变化比较棘手,您至少可以避免在任何 bfcache 导航中发生改变,从而降低影响。

向后和向前导航在许多网站上很常见。例如,返回到某个内容页面、某个类别页面或搜索结果。

在 Chrome 中推出此功能后,我们发现 CLS 有了显著的改进

默认情况下,所有浏览器都会使用 bfcache,但有些网站由于各种原因而不符合使用 bfcache。如需详细了解如何测试和找出导致 bfcache 使用的问题,以确保您充分利用此功能来帮助获得网站总体 CLS 得分,请参阅 bfcache 指南

总结

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