优化 Cumulative Layout Shift

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

发布时间:2020 年 5 月 5 日,上次更新时间:2025 年 2 月 7 日

Cumulative Layout Shift (CLS) 是三项 Core Web Vitals 指标之一。它通过以下方式衡量内容的不稳定性:将视口中可见内容的偏移量与受影响元素的移动距离相结合。

布局偏移可能会让用户分心。假设您正在阅读一篇文章,突然间,网页上的元素四处移动,让您感到困惑,需要重新找到自己的位置。这种情况在网络上非常常见,包括在阅读新闻或尝试点击“搜索”或“添加到购物车”按钮时。这种体验在视觉上会让人感到不适和沮丧。当由于另一个元素突然添加到网页或调整大小而导致可见元素被迫移动时,通常会发生这种情况。

为了提供良好的用户体验,网站应尽力使至少 75% 的网页访问事件的 CLS 值不超过 0.1。

良好的 CLS 值低于 0.1,较差的值高于 0.25,介于两者之间的值需要改进
良好的 CLS 值是 0.1 或更低。较差的值大于 0.25。

与其他核心网页指标(以秒或毫秒为单位的时间值)不同,CLS 得分是一个无单位的值,它基于对内容移动量和移动距离的计算。

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

CLS 较差的最常见原因如下:

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

了解布局偏移的原因

在开始寻找常见 CLS 问题的解决方案之前,请务必先了解您的 CLS 得分以及发生位移的位置。

实验室工具中的 CLS 与实际环境中的 CLS

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

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

在网页加载期间,由于系统会提取所有必要的资源来初始呈现网页,因此布局偏移非常常见,但布局偏移也可能在初始加载后发生。许多加载后偏移可能是用户互动的结果,因此不会纳入 CLS 得分中,因为这些偏移是预期的偏移,前提是它们发生在相应互动后的 500 毫秒内。

不过,如果用户没有进行符合条件的互动,但页面上仍出现了用户意想不到的其他加载后位移,则可能会包含这些位移。例如,如果您进一步滚动页面,系统会加载延迟加载的内容,从而导致位移。加载后 CLS 的其他常见原因是过渡互动,例如单页应用上的过渡互动,这些互动所花费的时间超过了 500 毫秒的宽限期。

PageSpeed Insights 会在“了解真实用户的体验”部分中显示网址的用户感知 CLS,并在“诊断性能问题”部分中显示基于实验的加载 CLS。这些值之间的差异很可能是加载后 CLS 造成的。

PageSpeed Insights 显示网址级数据,突出显示实际用户 CLS,该值远大于 Lighthouse CLS
在此示例中,CrUX 测得的 CLS 比 Lighthouse 测得的 CLS 大得多。

识别加载 CLS 问题

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

显示 CLS 审核的 Lighthouse 屏幕截图,其中包含更多信息,可帮助您找出并解决 CLS 问题
Lighthouse 的详细 CLS 诊断信息。

开发者工具中的“性能”面板可提供有关布局偏移的丰富信息:

在 Chrome 开发者工具的“性能”面板中显示布局偏移记录。
在“性能”面板中记录新轨迹后,结果的布局偏移轨道会填充紫色条,显示 Layout Shift 集群。点击菱形会在摘要面板中显示偏移的动画效果和详细信息。

布局偏移会在布局偏移轨道中突出显示。紫线将轮班分组为轮班集群,菱形表示相应集群中的各个轮班。菱形的大小与变化幅度成正比,因此您可以重点关注变化幅度最大的数据。

点击某个位移后,系统会显示一个弹出式窗口,其中包含该位移的动画,并以紫色突出显示元素位移。

此外,Layout Shift 记录的摘要视图还包括开始时间、轮班得分以及轮班的元素。这对于详细了解加载 CLS 问题特别有用,因为使用重新加载性能配置文件可以轻松重现此问题。

此链接还指向左侧数据分析面板中显示的布局偏移的罪魁祸首数据分析,该数据分析会在顶部显示总 CLS,以及可能导致布局偏移的原因。

识别加载后 CLS 问题

如果 CrUX 和 Lighthouse CLS 得分不一致,通常表示存在加载后 CLS。如果没有实地数据,很难找出这些变化的原因。如需了解如何收集实地数据,请参阅衡量实地 CLS 元素

通过“性能”面板的实时指标视图,您可以与网页互动并监控 CLS 分数,以找出导致布局发生大幅偏移的互动。

在 Chrome 开发者工具的“性能”面板的实时指标屏幕中显示的布局偏移记录。
借助“性能”面板的实时指标视图,您可以在与网页互动的同时监控网页的 CLS 得分。

除了使用开发者工具之外,您还可以浏览网页,同时使用粘贴到控制台中的性能观测器记录布局偏移

设置好偏移监控后,您可以尝试重现任何加载后 CLS 问题。CLS 通常发生在用户滚动浏览网页时,当延迟加载的内容在没有预留空间的情况下完全加载时,就会发生 CLS。用户将指针悬停在内容上时,内容发生位移是另一种常见的加载后 CLS 原因。在上述任一互动期间发生的任何内容偏移均视为意外偏移,即使偏移发生在 500 毫秒内也是如此。

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

确定 CLS 的任何常见原因后,您还可以使用 Lighthouse 的时间段用户流程模式来确保引入布局偏移不会导致典型用户流程出现倒退。

衡量现场的 CLS 元素

在实际环境中监控 CLS 对于确定发生 CLS 的情况和缩小可能的原因范围非常有价值。与大多数实验室工具一样,现场工具仅测量发生变化的元素,但通常足以提供用于确定原因的信息。您还可以使用 CLS 字段测量结果来确定哪些问题需要优先修复。

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

CLS 的常见原因

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

未设置尺寸的图片

请务必为图片和视频元素添加 widthheight 大小属性。或者,使用 CSS aspect-ratio 或类似方法预留所需空间。此方法可确保浏览器在图片加载时能够在文档中分配正确的空间量。

未指定宽度和高度的图片。
指定了宽度和高度的图片。
Lighthouse 报告,显示了在图片上设置尺寸后,累积布局偏移 (CLS) 的前后影响
设置图片尺寸对 CLS 的 Lighthouse 6.0 影响。

图片上 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。

广告是导致网页布局偏移的最大因素之一。广告联盟和发布商通常支持动态广告尺寸。由于点击率更高,且参与竞价的广告更多,因此广告尺寸越大,效果和收入就越好。遗憾的是,由于广告会将您正在查看的可见内容挤到页面下方,这可能会导致用户体验欠佳。

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

处理这些问题的方法都类似。主要区别在于您可以对要插播的内容进行多大程度的控制。如果此元素是由广告合作伙伴等第三方插入的,您可能不知道将要插入的内容的确切大小,也无法控制这些嵌入内容中发生的任何布局偏移。

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

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

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

三部移动设备,第一部设备中只有文字内容,第二部设备中的文字内容向下移动,第三部设备中预留了占位符空间,可防止文字内容移动
预留广告空间可防止布局发生变化

您可能需要使用媒体查询来考虑不同外形规格的广告或占位符尺寸的细微差异。

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

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

如果未返回广告,请尝试通过显示占位符来避免收起预留空间。移除为元素预留的空间可能会导致与插入内容一样多的 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 字体之间的尺寸差异,详情请参阅改进的字体回退博文。
  • 字体加载 API 可以缩短获取必要字体所需的时间。
  • 使用 <link rel=preload> 尽早加载关键网页字体。预加载的字体更有可能满足首次绘制,在这种情况下不会发生布局偏移。

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

通过确保网页符合 bfcache 条件来减少 CLS

确保网页符合 back/forward 缓存 (bfcache) 的条件,是保持较低 CLS 得分的一种非常有效的技术。

在您离开网页后,bfcache 会将网页在浏览器内存中保留一小段时间,因此如果您返回这些网页,它们会恢复到您离开时的状态。这意味着完全加载的网页可立即显示,而不会出现因上述任何原因而在加载期间可能出现的偏移。

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

在许多网站上,返回和前进导航都是常见操作。例如,返回到目录页、类别页或搜索结果。

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

所有浏览器默认都会使用 bfcache,但有些网站由于各种原因而无法使用 bfcache。请参阅 bfcache 指南,详细了解如何测试和识别阻止使用 bfcache 的任何问题,以确保您充分利用此功能来提高网站的总体 CLS 分数。

总结

如本指南前文所述,您可以使用多种技巧来识别和改进 CLS。Core Web Vitals 中内置了一些容差,因此即使您无法完全消除 CLS,使用其中一些技巧也应该能够减少其影响。希望这能帮助您将网站保持在这些限制范围内,从而为网站用户打造更好的体验。