优化 Cumulative Layout Shift

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

布局偏移可能会分散用户的注意力。假设您在开始阅读一篇文章时突然元素在网页内四处移动,导致您迷失方向,需要再次找到相应位置。这在网络上非常常见,包括在阅读新闻或尝试点击“搜索”或“添加到购物车”按钮时。此类体验会造成视觉冲击和失望。通常,当可见元素因突然将另一个元素添加到页面中或调整大小而被强制移动时,就会出现这些错误。

为了提供良好的用户体验,网站必须至少有 75% 的网页访问的 CLS 不超过 0.1

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

与其他核心网页指标不同,后者是基于时间的值(以秒或毫秒为单位),CLS 得分是无单位的值,根据计算的内容偏移量和幅度得出。

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

导致 CLS 不佳的最常见原因包括:

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

了解布局偏移的原因

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

实验室工具与现场使用的 CLS

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

CrUX 是网页指标计划的官方数据集。这项指标在网页的整个生命周期中衡量 CLS,而不只是在实验室工具通常所衡量的初始网页加载期间进行衡量。

在网页加载期间布局偏移非常常见,因为此时系统获取了呈现网页所需的所有资源,但初始加载后也可能会发生布局偏移。许多加载后偏移是由用户互动导致的,因此会从 CLS 得分中排除。只要它们在该互动发生后的 500 毫秒内发生,就会算作“预期”偏移。

不过,如果没有符合条件的互动(例如,在用户滚动浏览网页时延迟加载的内容完全加载),则可能会出现意外的加载后偏移。加载后 CLS 的其他常见原因是转换之间的互动,例如在单页应用中进行的交互,需要的宽限期超过 500 毫秒。

PageSpeed Insights 的“了解真实用户遇到了什么情况”部分会显示用户感知的来自某个网址的 CLS,“诊断性能问题”部分会显示基于实验室的负载 CLS。 这些值之间的差异可能是由于加载后 CLS 造成的。

PageSpeed Insights 的屏幕截图,其中突出显示了实际用户 CLS(明显大于 Lighthouse CLS)的网址级数据
在此示例中,CrUX 测量的 CLS 比 Lighthouse 大得多。

确定负载 CLS 问题

当 CrUX 和 Lighthouse CLS 得分在 PageSpeed Insights 上相似,这通常意味着 Lighthouse 检测到了加载 CLS 问题。在这种情况下,Lighthouse 可提供两项审核服务来了解更多信息:一项针对因宽度和高度缺失而导致 CLS 的图像,一项针对页面加载期间发生变化的所有元素及其 CLS 贡献。如需查看这些审核,请按下图所示进行过滤:

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

开发者工具中的“Performance”面板也会在体验部分中突出显示布局偏移。Layout Shift 记录的摘要视图包含 CLS 得分,以及一个显示受影响区域的矩形叠加层。这些配置对于识别加载 CLS 问题特别有帮助,因为它们可让您通过重新加载性能配置文件来重现用户体验。

当展开“体验”部分时,“布局偏移”会记录 Chrome 开发者工具性能面板中的显示情况
在“Performance”面板中录制新的轨迹后,结果的 Experience 部分会填充一个红色条形,显示一条 Layout Shift 记录。点击记录即可显示详细信息(例如此图片中的“已移至”和“已移至”条目),深入了解受影响的元素。

确定加载后 CLS 问题

CrUX 和 Lighthouse CLS 得分不一致通常表示加载后 CLS。如果没有现场数据,跟踪这些变化可能会比较困难。如需了解如何收集现场数据,请参阅测量现场的 CLS 元素

Web Vitals Chrome 扩展程序可用于在您与网页互动时监控 CLS,无论是在平视显示中,还是在控制台中显示已偏移的元素的详细信息

作为使用该扩展程序的替代方案,您还可以使用粘贴到控制台的 Performance Observer 来浏览网页,同时记录布局偏移

设置偏移监控后,您可以尝试重现任何加载后 CLS 问题。CLS 通常发生在用户滚动页面时,即延迟加载的内容已完全加载,但没有预留空间。用户将鼠标悬停在其上时的内容偏移是加载后 CLS 的另一个常见原因。在上述任一互动期间,任何内容偏移都会被视为意外,即使发生在 500 毫秒内。

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

在确定导致 CLS 的常见原因后,您还可以使用 Lighthouse 的时间跨度用户流模式,确保布局偏移不会破坏典型的用户流。

测量现场的 CLS 元素

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

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

导致 CLS 的常见原因

本部分概述了导致 CLS 的一些较常见原因,以及避免 CLS 的策略。

没有尺寸的图片

请务必在图片和视频元素中添加 widthheight 尺寸属性,或使用 CSS aspect-ratio 预留所需的空间。这样,浏览器就可以在图片加载时分配文档中的正确空间量。

未指定宽度和高度的图片。

已指定宽度和高度的图片。

Lighthouse 报告显示了在图像上设置尺寸后对 Cumulative Layout Shift 之前/之后的影响
Lighthouse 6.0 对在 CLS 上设置图片尺寸的影响。

widthheightaspect-ratio

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

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

此示例中的 widthheight 不包含单位。这些“像素”尺寸可确保浏览器预留 640x360 的区域。无论真实尺寸是否与图片大小一致,图片都会拉伸以适应此空间。

在引入自适应设计时,开发者开始使用 CSS 而不是 widthheight 来调整图片大小:

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

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

设置图片尺寸的最佳做法

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

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

然后,浏览器会根据元素现有的 widthheight 属性添加默认宽高比,以便在开始计算布局时确定为图片预留多少空间。

由于主流浏览器在处理 HTML 时会计算默认宽高比,因此每个浏览器显示该值的方式会略有不同。(如需详细了解发生这种情况的原因,请参阅宽度和高度的呈现提示。)

例如,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 现在支持对 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。

广告是导致网页布局发生变化的最大因素之一。广告联盟和发布商通常支持动态广告尺寸,并且较大的广告通常会比较小的广告获得更多的收入。但是,广告突然加载并将可见内容下推,会影响用户体验。

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

处理这些任务的技术都相似。主要区别在于您对插入内容的控制程度。第三方(如广告合作伙伴)通常不会为您提供任何有关插入的内容的实用信息,也不会为您提供有关这些嵌入导致的布局偏移的任何控制。

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

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

这可以很简单,例如添加 min-height 样式以预留空间;对于广告等自适应内容,可以使用新的 aspect-ratio CSS 属性,方法与浏览器自动使用图片属性类似。

第三台设备上只有文本内容的三台移动设备。这会在第二台设备上移位,在第三台设备上预留带有占位符的空间可以防止移位。
为广告预留空间可以避免布局偏移。

您可能需要使用媒体查询找出各种设备类型上广告或占位符尺寸的细微差异。

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

您可以将初始大小设置为要使用的最小大小,对于较大内容,可接受一定程度的偏移。与空元素的默认大小为 0 像素相比,使用 min-height 可让父元素根据需要进行扩展,同时降低布局偏移的影响。

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

将延迟加载的内容放在视口中靠下的位置

与在视口中下方注入的内容相比,在靠近视口顶部进行动态注入的内容通常会导致更大的布局偏移。不过,在视口的任何位置注入内容仍会导致发生一定程度的偏移。如果您无法为注入的内容预留空间,我们建议将其放置在页面上靠后的位置,以减少影响。

重叠式横幅内容

网页上意外显示的横幅广告和表单是导致意外布局偏移的另一个常见原因。

没有预留空间的动态内容。

如果您无法为此类内容预留空间,则可以改为将其叠加在现有内容上,这样就不会成为文档流程的一部分。如需有关何时使用此方法的建议,请参阅 Cookie 通知最佳实践

让用户互动触发预期的布局偏移

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

  • 在固定大小的容器中将旧内容替换为新内容,或使用轮播界面在过渡后移除旧内容。请务必停用所有链接和控件,直到转换完成为止,以防止在加载新内容时意外执行点击或点按操作。
  • 让用户启动新内容的加载,例如使用加载更多刷新按钮,因此这种转变并不奇怪。我们建议在用户互动之前预提取新内容,使其立即显示。请注意,在用户输入内容时在 500 毫秒内的布局偏移不会计入 CLS。
  • 顺畅地加载屏幕外的内容,并在上面叠加一条通知,告知用户该内容(例如,使用 Scroll to top 按钮)。
不会导致 Twitter 和 Chloé 网站出现意外布局偏移的动态内容加载示例
不会导致布局意外偏移的动态内容加载示例。左图:Twitter 上正在加载实时 Feed 内容。右图:Chloé 网站上的“Load More”示例。了解 YNAP 团队如何 在加载更多内容时针对 CLS 进行优化

动画

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

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

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

网络字体

在下载网页字体之前,通常通过以下两种方式之一处理下载和渲染网页字体:

  • 使用无样式文本的 Flash (FOUT) 将后备字体与网页字体进行交换。
  • “不可见”文本使用回退字体显示,直到有网页字体可用且该文本通过不可见文本闪烁 (FOIT) 变为可见为止。

这两种方法都会导致布局偏移。即使文本不可见,它仍会使用回退字体进行布局,因此当网页字体加载时,文本块和周围内容会按照与可见字体相同的方式转变。

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

  • font-display: optional 会导致仅当网页字体在初始布局时可用时,系统才会使用它。
  • 使用与网页字体类似的后备字体。例如,使用 font-family: "Google Sans", sans-serif; 会使浏览器在 "Google Sans" 加载时使用 sans-serif 后备字体。如果未指定回退字体(仅使用 font-family: "Google Sans"),会导致 Chrome 使用默认的 Serif 字体,这导致了更糟糕的匹配效果。
  • 使用新的 size-adjustascent-overridedescent-overrideline-gap-override API,应最大限度地减小回退字体与网页字体之间的大小差异。如需了解详情,请参阅改进的字体回退
  • Font Loading API 可以缩短字体加载时间。
  • 使用 <link rel=preload> 尽早加载关键网页字体。预加载的字体更有可能为首次绘制做好准备,并且不会导致布局偏移。

如需了解详情,请参阅字体最佳实践

确保您的网页符合 bfcache 的条件

保持较低的 CLS 得分的一种高效方法是确保您的网页有资格被往返缓存 (bfcache) 储存。

bfcache 在您离开浏览器后会在浏览器内存中保留网页一小段时间,以便在您返回页面时,它们可以恢复原样恢复。也就是说,完全加载的网页可以即时访问,而不会在网页加载时发生任何变化。

虽然这仍然可能意味着初始网页加载会产生布局偏移,但它可以让用户避免重复看到相同的布局偏移。这样可以减少在其他方面可能无法解决的布局偏移的影响。

往返导航在许多网站上都很常见,例如返回内容页面、类别页面或搜索结果时。

默认情况下,所有浏览器都会使用 bfcache,但出于各种原因,有些网站不符合使用 bfcache 的条件。如需详细了解如何测试并确定阻止使用 bfcache 的任何问题,请参阅这篇 bfcache 文章