优化累积布局偏移

了解如何避免突发的布局偏移,从而改善用户体验

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

累积布局偏移 (CLS) 是三大 Core Web Vitals 指标之一。它通过结合视口中可见内容的偏移量以及受影响元素移动的距离来衡量内容的不稳定性。

布局偏移可能会分散用户的注意力。想象一下,您开始阅读一篇文章,突然页面上的元素四处移动,让您不知所措,需要重新找到您的位置。这在 Web 上非常常见,包括阅读新闻或尝试单击“搜索”或“添加到购物车”按钮时。此类体验在视觉上令人感到突兀和沮丧。它们通常是由于可见元素被迫移动而引起的,因为另一个元素突然添加到页面或调整了大小。

为了提供良好的用户体验,站点应努力使至少 75% 的页面访问的 CLS 值保持在 0.1 或更低。

Good CLS values are under 0.1, poor values are greater than 0.25 and anything in between needs improvement
良好的 CLS 值为 0.1 或更低。较差的值大于 0.25。

与其他以秒或毫秒为单位的时间值 Core Web Vitals 不同,CLS 分数是一个无单位值,它基于对内容偏移量和偏移距离的计算。

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

导致 CLS 较差的最常见原因是

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

了解布局偏移的原因

在开始研究常见 CLS 问题的解决方案之前,务必了解您的 CLS 分数以及偏移的来源。

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

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

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

布局偏移在页面加载期间非常常见,因为所有必要的资源都会被提取以初始渲染页面,但布局偏移也可能在初始加载后发生。许多加载后偏移可能是 用户交互的结果,因此将从 CLS 分数中排除,因为它们是预期的偏移 - 只要它们发生在交互后的 500 毫秒内。

但是,用户未预料到的其他加载后偏移可能会被包括在内,因为没有符合条件的交互 - 例如,如果您进一步滚动页面并且延迟加载的内容被加载,并且这会导致偏移。加载后 CLS 的其他常见原因是在过渡的交互中,例如在单页应用程序上,这需要超过 500 毫秒的宽限期。

PageSpeed Insights 在其“了解您的真实用户体验”部分显示了来自 URL 的用户感知 CLS,并在其“诊断性能问题”部分显示了基于实验室的加载 CLS。这些值之间的差异可能是加载后 CLS 的结果。

PageSpeed Insights showing URL-level data highlighting the real user CLS which is considerably larger than the Lighthouse CLS
在此示例中,CrUX 测量的 CLS 比 Lighthouse 大得多。

识别加载 CLS 问题

当 PageSpeed Insights 的 CrUX 和 Lighthouse CLS 分数大致一致时,这通常表明存在 Lighthouse 检测到的加载 CLS 问题。在这种情况下,Lighthouse 将通过两项审核来提供更多信息,以了解由于缺少宽度和高度而导致 CLS 的图片,并列出页面加载时所有偏移的元素及其 CLS 贡献。您可以通过筛选 CLS 审核来查看这些审核

Lighthouse Screenshot showing the CLS audits providing more information to help you identify and address CLS issues
Lighthouse 的详细 CLS 诊断。

DevTools 中的 性能面板 提供了有关布局偏移的丰富信息

Layout Shift records being displayed in the Chrome DevTools performance panel.
在性能面板中记录新跟踪后,结果的布局偏移轨道将填充紫色条,显示 Layout Shift 集群。单击菱形会在摘要面板中显示偏移的动画和详细信息。

布局偏移在布局偏移轨道中突出显示。紫色线条将偏移分组为偏移集群,菱形显示该集群中的各个偏移。菱形的大小与偏移的大小成正比,使您可以专注于最大的偏移。

单击偏移会显示一个弹出窗口,其中包含偏移的动画并以紫色突出显示元素偏移。

此外,Layout Shift 记录的 摘要视图包括开始时间、偏移分数以及偏移的元素。这对于更详细地了解加载 CLS 问题特别有帮助,因为这很容易通过重新加载性能配置文件来复制。

这也链接到左侧 Insights 面板中显示的 Layout shift culprits 洞察,该洞察显示顶部的总 CLS 以及布局偏移的可能原因。

识别加载后 CLS 问题

CrUX 和 Lighthouse CLS 分数之间的不一致通常表示加载后 CLS。如果没有实际环境数据,这些偏移可能难以追踪。有关收集实际环境数据的信息,请参阅 在实际环境中测量 CLS 元素

性能面板的实时指标视图使您可以与页面交互并监控 CLS 分数,以识别导致大型布局偏移的交互。

Layout Shift records being displayed in the live metrics screen of Chrome DevTools performance panel.
性能面板的实时指标视图允许在与网页交互时监控网页的 CLS 分数。

作为使用 DevTools 的替代方法,您可以在浏览网页时,将粘贴到控制台中的 使用 Performance Observer 记录布局偏移

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

有关更多信息,请参阅 调试布局偏移

在您确定了 CLS 的任何常见原因后,还可以使用 Lighthouse 的时间跨度用户流模式,以确保典型的用户流不会因引入布局偏移而退化。

在实际环境中测量 CLS 元素

在实际环境中监控 CLS 对于确定 CLS 在何种情况下发生以及缩小可能的原因范围非常有价值。与大多数实验室工具一样,实际环境工具仅测量偏移的元素,但这通常提供足够的信息来识别原因。您还可以使用 CLS 实际环境测量结果来确定哪些问题是修复的最高优先级。

web-vitals 库具有 归因函数,可让您收集此附加信息。有关更多信息,请参阅 在实际环境中调试性能。其他 RUM 提供商也已开始类似地收集和呈现此数据。

CLS 的常见原因

确定 CLS 的原因后,您可以开始着手解决这些问题。在本节中,我们将展示 CLS 的一些更常见的原因,以及您可以采取哪些措施来避免它们。

没有尺寸的图片

始终在您的图片和视频元素上包含 widthheight 尺寸属性。或者,使用 CSS aspect-ratio 或类似方法保留所需的空间。这种方法确保浏览器可以在图片加载时在文档中分配正确的空间量。

没有指定宽度和高度的图片。
指定了宽度和高度的图片。
Lighthouse report showing the before/after impact to Cumulative Layout Shift after setting dimensions on images
在 CLS 上设置图片尺寸的 Lighthouse 6.0 影响。

图片上 widthheight 属性的历史

在 Web 的早期,开发人员会在他们的 <img> 标签中添加 widthheight 属性,以确保在浏览器开始获取图片之前在页面上分配足够的空间。这将最大限度地减少重排和重新布局。

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

此示例中的 widthheight 不包含单位。这些“像素”尺寸将确保浏览器在页面布局中保留 640x360 区域。无论真实尺寸是否匹配,图片都会拉伸以适合此空间。

响应式 Web 设计 推出时,开发人员开始忽略 widthheight,并开始使用 CSS 来调整图片大小

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

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

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

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

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

了解图片的宽高比允许浏览器计算并保留足够的高度和相关区域空间。

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

由于现代浏览器根据图片的 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 完全不会在其 Inspector 面板中显示此计算出的 aspect-ratio,但确实将其用于布局。

前面代码中的 auto 部分很重要,因为它会导致图片尺寸在图片下载后覆盖默认宽高比。如果图片尺寸不同,这仍然会在图片加载后导致一些布局偏移,但这可以确保在 HTML 不正确的情况下,图片宽高比仍然在其可用时使用。即使实际宽高比与默认值不同,它仍然比未提供尺寸的图片的 0x0 默认大小导致的布局偏移要小。

有关宽高比的精彩深入探讨以及围绕响应式图片的进一步思考,请参阅 使用媒体宽高比实现无卡顿页面加载

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

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

响应式图片呢?

使用 响应式图片 时,srcset 定义了您允许浏览器在其中选择的图片以及每张图片的大小。为了确保可以设置 <img> width 和 height 属性,每张图片应使用相同的宽高比。

<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 上布局偏移的最大贡献者之一。广告网络和发布商通常支持动态广告尺寸。由于更高的点击率和更多在竞价中竞争的广告,广告尺寸提高了性能和收入。不幸的是,这可能会导致用户体验不佳,因为广告会将您正在查看的可见内容向下推。

可嵌入的小部件允许您在页面上包含可移植的 Web 内容,例如来自 YouTube 的视频、来自 Google 地图的地图和社交媒体帖子。但是,这些小部件通常在加载之前不知道其内容有多大。因此,提供嵌入的平台并不总是为其小部件保留空间,这会在它们最终加载时导致布局偏移。

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

为后期加载的内容保留空间

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

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

Three mobile devices with just text content in the first device, this is shifted down in the second device, and reserving space with a placeholder as shown in the third device prevents the shift
为广告保留空间可以防止布局偏移

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

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

您可以改为将初始尺寸设置为将要使用的最小尺寸,并接受较大内容的一些偏移级别。与空元素的 0px 默认尺寸相比,如前所述,使用 min-height 允许父元素根据需要增长,同时减少布局偏移的影响。

尝试避免通过显示占位符来折叠保留空间,例如,如果未返回广告。删除为元素预留的空间可能会导致与插入内容一样多的 CLS。

将后期加载的内容放置在视口中较低的位置

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

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

当您尝试加载站点时,您可能已经体验过由于在视口顶部或底部弹出的 UI 引起的布局偏移。与广告类似,这种情况通常发生在横幅和表单上,它们会偏移页面的其余内容

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

如果您需要显示这些类型的 UI 辅助功能,请提前在视口中为其保留足够的空间(例如,使用占位符或骨架 UI),以便在加载时,它不会导致页面中的内容意外地四处移动。或者,确保元素不是文档流的一部分,方法是在合理的情况下覆盖内容。有关这些类型组件的更多建议,请参阅 Cookie 通知最佳实践 文章。

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

  • 在固定大小的容器中用新内容替换旧内容,或使用轮播并在过渡后删除旧内容。请记住,在过渡完成之前禁用任何链接和控件,以防止在新内容进入时意外单击或点击。
  • 让用户发起新内容的加载,这样他们就不会对偏移感到惊讶(例如,使用“加载更多”或“刷新”按钮)。建议在用户交互之前预取内容,以便内容立即显示出来。提醒一下,用户输入后 500 毫秒内发生的布局偏移 不计入 CLS。
  • 无缝地在屏幕外加载内容,并向用户叠加一个通知,告知内容可用(例如,使用“滚动到顶部”按钮)。
Examples of dynamic content loading without causing unexpected layout shifts from Twitter and the Chloé website
动态内容加载而不引起意外布局偏移的示例。左图:Twitter 上加载的实时源内容。右图:Chloé 网站上的“加载更多”示例。了解 YNAP 团队如何在加载更多内容时 优化 CLS

动画

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

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

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

Web 字体

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

  • 后备字体与 Web 字体交换,导致出现未设置样式的文本闪烁 (FOUT)。
  • 在使用后备字体显示“不可见”文本,直到 Web 字体可用并使文本可见(FOIT - 不可见文本闪烁)。

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

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

  • font-display: optional 可以避免重新布局,因为仅当 Web 字体在初始布局时可用时才使用它。
  • 确保使用适当的后备字体。例如,使用 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> 尽早加载关键 Web 字体。预加载的字体更有可能在首次绘制时就绪,在这种情况下,不会发生布局偏移。

阅读字体最佳实践,了解其他字体最佳实践。

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

一种保持较低 CLS 分数的非常有效的方法是确保您的网页符合后退/前进缓存 (bfcache) 的条件。

bfcache 会将页面保存在浏览器内存中一小段时间,以便您在离开后返回时,页面将完全按照您离开时的状态恢复。这意味着完全加载的页面可以立即使用,而不会出现通常在加载期间由于前面给出的任何原因而可能出现的任何偏移。

虽然这仍然可能意味着初始页面加载会遇到布局偏移,但当用户回溯页面时,他们不会重复看到相同的布局偏移。您应该始终力求避免甚至在初始加载时出现偏移,但在更难完全解决的情况下,您至少可以通过避免在任何 bfcache 导航中出现偏移来减少影响。

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

此功能推广到 Chrome 后,我们看到了 CLS 的显著改进

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

结论

如本指南前面详细介绍的,有许多技术可以识别和改进 CLS。核心 Web 指标中内置了容差,因此即使您无法完全消除 CLS,使用其中一些技术也应该可以减少影响。这有望使您保持在这些限制范围内,从而为您网站的用户创造更好的体验。