“我正要点它,为什么它动了 😭”
布局偏移会造成用户困惑。想象一下你正在阅读文章,然后一个元素图片出现,一下子把你正在看的内容顶了出去,然后你就不得不再去找到你刚才阅读到的地方。这个在web应用上很正常,当你阅读新闻的时候,正在准备点击查询和添加到购物车的时候。这种体验让人非常不爽。当一个元素突然出现或者页面尺寸改变时,就会导致你当前视图中的元素就会被偏移出去。
CLS-CWV中的一项关键指标,通过用户输入后500ms内的偏移量来衡量视图稳定性。它主要针对视图中元素的偏移量以及影响到的元素的范围。在这篇文章中,我们将介绍优化布局偏移的常见问题。
image.png
导致CLS较差的主要原因:

  • 图片没有尺寸声明
  • 没有尺寸的广告和iframe
  • 动态注入的内容
  • 会导致FOIT/FOUT的字体
  • 在更新DOM前等待网路响应的操作

    未声明尺寸的图片

    摘要:始终在图像和视频元素上声明width和height大小属性。或者,使用 CSS aspect ratio boxes 保留所需的空间。这种方法确保浏览器可以在加载图像时在文档中分配正确的空间大小。 1.webm未指定宽度和高度的图像。 2.webm指定宽度和高度的图像。
    image.png
    Lighthouse 6.0下设置图像尺寸对CLS的影响

历史因素

在 Web 的早期,开发人员会在他们的标签中添加width和height属性,优化CLS - 图5以确保在浏览器开始获取图像之前在页面上分配了足够的空间。这将最大限度地减少回流和重绘。

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

您可能会注意到width,height以上不包括单位。这些“像素”尺寸将确保保留 640x360 的区域。无论真实尺寸是否匹配,图像都会拉伸以适应此空间。
响应式设计被提出后,开发者开始省略width和height使用CSS来调整图像:

  1. img {
  2. width: 100%; /* or max-width: 100%; */
  3. height: auto;
  4. }

这种方法的一个缺点是,只有在开始下载图像并且浏览器可以确定其尺寸后才能为图像分配空间。随着图像加载,页面会随着每个图像出现在屏幕上而重排。文本突然出现在屏幕上变得很常见。这不是一个很好的用户体验。
这就是宽高比的用武之地。图像的宽高比是其宽度与高度的比率。通常将此表示为由冒号分隔的两个数字(例如 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

知道纵横比允许浏览器计算并为高度和相关区域保留足够的空间。

最佳实践

现代浏览器根据图像的宽度和高度属性设置图像的默认纵横比,因此设置它们可以防止布局偏移。很感谢CSS工作组的贡献,这样开发者只需要设置width和height即可:

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

所有浏览器的UA 样式表都根据元素的现有和属性添加了默认纵横比:width height

  1. img {
  2. aspect-ratio: attr(width) / attr(height);
  3. }

这会在图像加载之前根据width和height属性计算纵横比。它在布局计算的一开始就提供此信息。一旦图像被告知具有特定宽度(例如width: 100%),就会使用纵横比来计算高度。
如果你狠难理解纵横比,你可以从calculator 处获得帮助。
上面的图像纵横比在Chrome、Firefox和Safari中都有所实现。
要深入了解纵横比并进一步考虑响应式图像,请参阅 jank-free page loading with media aspect ratios
如果您的图像在容器中,您可以使用 CSS 将图像的大小调整为该容器的宽度。我们设置height: auto;避免设置图像高度为固定值(例如360px)

  1. img {
  2. height: auto;
  3. width: 100%;
  4. }

响应式图片
当使用响应式图片时,你可以设置srcset属性来定义多个图片,这样浏览器会根据尺寸自动选择对应的图片,确保图片的宽高都有设置,同时一定要使用横纵比。

  1. <img
  2. width="1000"
  3. height="1000"
  4. src="puppy-1000.jpg"
  5. srcset="puppy-1000.jpg 1000w, puppy-2000.jpg 2000w, puppy-3000.jpg 3000w"
  6. alt="Puppy with balloons"
  7. />

什么是美术设计问题?
在小视窗的设备上,期望显示图片的裁剪部分,在大视窗的设备上,显示完整图片。

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

这些图像很可能具有不同的纵横比,浏览器仍在评估此处最有效的解决方案应该是什么,包括是否应在所有来源上指定尺寸。在确定解决方案之前,这里仍然可以重新布局。

无尺寸的广告、嵌入元素和 iframe 📢😱

广告

广告是页面版式变化的最大贡献者之一。广告和发布商通常支持动态的广告尺寸。由于更高的点击率和更多的广告在竞价中竞争,广告尺寸提高了性能/收入。不幸的是,由于广告将您正在查看的可见内容推送到页面下方,这可能会导致用户体验不佳。
在整个广告的存活周期内,有许多地方会导致布局偏移:

  • 当网站在 DOM 中插入广告容器时
  • 当网站使用第一方代码调整广告容器的大小时
  • 当广告代码库加载(并调整广告容器的大小)时
  • 当广告填满容器时(如果最终广告的尺寸不同,则调整尺寸)

好消息是网站可以遵循最佳做法来减少广告偏移。网站可以通过以下方式缓解这些布局变化:

  • 为广告位静态预留空间。
    • 换句话说,在加载广告标记库之前设置元素样式。
    • 如果在内容流中放置广告,请通过保留广告位大小来确保消除变化。如果在屏幕外加载,这些广告不应导致布局偏移。
  • 在视窗顶部附近放置非fiexd布局的广告时要小心。
    • 在下面的示例中,建议将广告移动到“世界视野”徽标下方,并确保为广告位预留足够的空间。
  • 通过显示占位符来避免在广告位可见时没有返回广告的情况下折叠保留的空间。
  • 通过为广告位保留尽可能大的尺寸来消除变化。
    • 这个虽然有用,但如果较小的广告创意填满了广告位,则可能会出现空白区域。
  • 根据历史数据为广告位选择最可能的尺寸。

如果广告位不太可能填满,一些网站会发现开始的时候折叠广告位可以减少布局变化。除非您自己控制广告投放,否则没有一种简单的方法可以每次都选择准确的尺寸。

3.webm未预留足够空间的广告 4.webm预留足够空间的广告。
image.png
Lighthouse 6.0 保留空间与否对CLS的影响

为广告位静态预留空间

将相同大小的静态样式插槽 DOM 元素传递给您的标签。这可以帮助确保你的依赖在加载的时候不造成布局偏移。如果你不这样做的话,这个库在它的元素加载的时候可能会造成元素偏移。
同时也要考虑一下较小的广告的尺寸。如果有较小的广告的时候,应当为它的父级容器设置稍大一点的尺寸以防止偏移。这种方法的缺点是它会增加空白空间,所以请注意这里要做一些衡量。

避免在视窗顶部防止广告

靠近视口顶部的广告可能会比中间的广告引起更大的布局偏移。这是因为顶部的广告通常在下方有更多的内容,这意味着当广告引起移动时,更多的元素会移动。相反,靠近视口中间的广告可能不会移动那么多的元素,因为它上面的内容不太可能移动。

嵌入元素和 iframe

可嵌入小部件允许您在页面中嵌入可移植的 Web 内容(例如,来自 YouTube 的视频、来自 Google 地图的地图、社交媒体帖子等)。这些嵌入可以采用多种形式:

  • HTML 回调和 JavaScript 标签将回调函数转换为嵌入元素
  • 内联 HTML 片段
  • iframe 嵌入

这些嵌入通常事先不知道嵌入有多大(例如,在社交媒体帖子的情况下 - 它是否有嵌入的图像?视频?多行文本?)。因此,提供嵌入的平台并不总是为其嵌入保留足够的空间,并且在最终加载时可能导致布局偏移。

5.webm嵌入而不保留空间。 6.webm嵌入保留空间。
image.png
Lighthouse 6.0 下是否保留空白对CLS的影响
要解决此问题,您可以通过使用带有预先计算好尺寸的占位符或者回调函数来优化 CLS。你可以用以下方式优化:

  • 通过使用浏览器开发人员工具检查元素来获取最终需要设置的高度
  • 一旦嵌入加载,包含的 iframe 将自动加载调整大小以适合其内容。

记下尺寸并相应地为嵌入的占位符设置样式。您可能需要使用媒体查询来考虑不同设备下广告的尺寸。

动态内容注入

摘要:禁止在已存在的元素上面插入新元素,除非有用户触发交互的时候可以。这可以确保你的元素偏移是在可预期的范围内的。
当你在加载一个网站时你可能遇到过由于在视窗底部或者顶部弹窗所导致的布局偏移。广告同理,轮播和表单经常会造成相关位移:

  • 来注册我们的时讯吧!
  • 相关内容展示
  • 安装我们的移动应用
  • 我们正在处理订单
  • GDPR 通知 7.webm如果你需要展示这一类元素,可以提前预留一定位置占位(占位符和骨架屏),这样就可以在加载时不会造成一些令人奇怪的位移。

网络字体导致 FOUT/FOIT

下载和渲染 Web 字体可能会导致布局变化:

  • 后备字体替换为新字体(FOUT - 无样式文本的闪烁)
  • 显示“不可见”文本,直到呈现新字体(FOIT - 不可见文本的闪烁)

以下工具可以帮助您最大程度地减少这种情况:

  • font-display允许你修改的自定义字体呈现行为与价值观,例如auto,swap,block,fallback和optional。不幸的是,所有这些值(除了optional)都可能导致以上述方式之一重新布局。
  • 字体加载API可以减少需要得到必要的字体的时间。

从 Chrome 83 开始,我也可以推荐以下内容:

  • 使用提前加载关键的Web字体
  • 结合和font-display: optional

阅读Prevent layout shifting and flashes of invisible text (FOIT) by preloading optional fonts了解更多细节。

动画🏃‍♀️

摘要:使用transform的动画而不是会造成偏移的属性动画。
CSS 属性值的更改可能需要浏览器对这些更改做出反应。许多值会触发重新布局、绘制和合成,例如box-shadow和box-sizing。许多 CSS 属性可以以成本较低的方式进行更改。
要了解有关哪些 CSS 属性触发布局的更多信息,请参阅CSS TriggersHigh-performance animations

开发者工具🔧

很高兴与大家分享,有许多工具可用于测量和调试累积布局偏移 (CLS)。
Lighthouse 6.0及更高版本支持在实验室环境中测量 CLS。此版本还将突出显示导致布局偏移最多的节点。
image.png
自 Chrome 84 起,DevTools 中的Performance 面板突出显示了Experience部分中的布局转换。记录的Summary视图Layout Shift包括累积布局转换分数以及显示受影响区域的矩形叠加。
image.png
在 Performance 面板中记录新跟踪后,结果的Experience部分将填充一个显示Layout Shift记录的红色条。单击记录可让您深入了解受影响的元素(例如注意移动自/移至条目)。
使用Chrome 用户体验报告也可以测量在原始级别聚合的真实 CLS 。CrUX CLS 数据可通过 BigQuery 获得,并且可以使用查看 CLS 性能的示例查询。
这就是本指南的内容。我希望它有助于让你的页面不那么诡异:)