调试布局偏移

了解如何识别和修正布局偏移。

发布时间:2021 年 3 月 11 日;上次更新时间:2025 年 2 月 7 日

本文的第一部分介绍了用于调试布局偏移的工具,第二部分介绍了在确定布局偏移原因时应遵循的思维过程。

您可以使用布局不稳定性 API 或 DevTools 等工具来调试布局偏移,这些工具会以更易于理解的格式汇总此 API 中的数据。

Layout Instability API 是用于衡量和报告布局偏移的浏览器机制。用于调试布局偏移的所有工具(包括 DevTools)最终都基于布局不稳定性 API 构建。不过,由于 Layout Instability API 的灵活性,直接使用它是一款强大的调试工具。

用法

用于衡量累积布局偏移 (CLS) 的代码代码段也可以用于调试布局偏移。以下代码段会将有关布局偏移的信息记录到控制台。通过检查此日志,您可以了解布局偏移发生的时间、地点和方式。

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

运行此脚本时,请注意以下事项:

  • buffered: true 选项表示 PerformanceObserver 应检查浏览器的性能条目缓冲区,以查找在观察器初始化之前创建的性能条目。因此,PerformanceObserver 会报告在其初始化之前和之后发生的布局偏移。在检查控制台日志时,请注意这一点。最初出现大量布局偏移可能反映的是报告积压,而不是突然出现大量布局偏移。
  • 为避免影响性能,PerformanceObserver 会等到主线程空闲时才报告布局偏移。因此,布局转换发生时与在控制台中记录布局转换时之间可能会有短暂的延迟,具体取决于主线程的繁忙程度。
  • 此脚本会忽略在用户输入后 500 毫秒内发生的布局偏移,因此这些偏移不会计入 CLS。

系统会结合使用两个 API(即 LayoutShiftLayoutShiftAttribution 接口)来报告布局偏移相关信息。以下各部分将更详细地介绍这些接口。

LayoutShift

系统会使用 LayoutShift 接口报告每一次布局偏移。条目的内容如下所示:

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

上一个条目表示布局偏移,其中三个 DOM 元素更改了位置。此特定布局偏移的布局偏移分数为 0.175

以下是与调试布局偏移最相关的 LayoutShift 实例属性:

属性 说明
sources sources 属性会列出在布局转换期间移动的 DOM 元素。此数组最多可包含 5 个来源。如果有超过 5 个元素受到布局偏移的影响,系统会报告导致布局偏移的 5 个主要原因(以对布局稳定性的影响为衡量标准)。系统会使用 LayoutShiftAttribution 接口报告此类信息(详见下文)。
value value 属性会报告特定布局偏移的布局偏移得分
hadRecentInput hadRecentInput 属性指示在用户输入后的 500 毫秒内是否发生了布局偏移。
startTime startTime 属性指示布局偏移发生的时间。startTime 以毫秒为单位,相对于网页加载启动时间进行测量。
duration duration 属性将始终设置为 0。此属性从 PerformanceEntry 接口继承而来(LayoutShift 接口扩展了 PerformanceEntry 接口)。不过,“时长”概念不适用于布局偏移事件,因此将其设置为 0。如需了解 PerformanceEntry 接口,请参阅规范

LayoutShiftAttribution

LayoutShiftAttribution 接口用于描述单个 DOM 元素的单次偏移。如果多个元素在布局偏移期间发生偏移,sources 属性将包含多个条目。

例如,以下 JSON 对应于一个来源的布局偏移:<div id='banner'> DOM 元素从 y: 76 向下偏移到 y:246

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

node 属性用于标识发生偏移的 HTML 元素。在 DevTools 中将鼠标悬停在此属性上会突出显示相应的页面元素。

previousRectcurrentRect 属性用于报告节点的大小和位置。

  • xy 坐标分别报告元素左上角的 x 坐标和 y 坐标
  • widthheight 属性分别报告元素的宽度和高度。
  • toprightbottomleft 属性会报告与元素的给定边对应的 x 或 y 坐标值。也就是说,top 的值等于 ybottom 的值等于 y+height

如果 previousRect 的所有属性都设为 0,则表示该元素已移至视野范围内。如果 currentRect 的所有属性都设为 0,则表示该元素已移出视野。

在解读这些输出时,最重要的一点是,列为来源的元素是布局偏移期间发生偏移的元素。不过,这些元素可能只是间接与布局不稳定的“根本原因”相关。以下是一些示例。

示例 1

系统会报告此布局偏移,并提供一个来源:元素 B。不过,导致这种布局偏移的根本原因是元素 A 的大小发生了变化。

显示元素尺寸变化导致布局偏移的示例

示例 2

在此示例中,系统会报告两个来源的布局偏移:元素 A 和元素 B。导致此布局偏移的根本原因是元素 A 的位置发生了变化。

显示元素位置变化导致布局偏移的示例

示例 3

此示例中的布局偏移将报告一个来源:元素 B。更改元素 B 的位置导致了此布局偏移。

显示元素位置变化导致布局偏移的示例

示例 4

虽然元素 B 会更改大小,但在此示例中不会发生布局偏移。

示例:元素更改大小但未导致布局偏移

查看演示,了解 Layout Instability API 如何报告 DOM 更改

开发者工具

开发者工具提供了多种工具来帮助调试布局偏移。

“效果”面板

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

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

在能够可靠地重现布局偏移后,您可以执行轨迹跟踪,以获取更多详细信息:

Chrome DevTools 性能面板中显示的布局偏移记录。
在“性能”面板中记录新的轨迹后,结果的布局偏移轨道会填充紫色条,显示 Layout Shift 集群。点击钻石图标会在摘要面板中显示相应班次的动画和详细信息。

布局偏移轨道中会突出显示布局偏移。紫色线条组会转变为偏移集群,其中钻石表示该集群中的各个偏移。钻石的大小与偏移量成正比,以便您重点关注偏移量最大的数据点。

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

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

此图表还会链接到左侧数据分析面板中显示的布局偏移原因数据分析,该数据分析会在顶部显示总 CLS 以及布局偏移的可能原因。

如需详细了解如何使用效果面板,请参阅效果分析参考文档

突出显示布局偏移区域

突出显示布局偏移区域是一种有用的技术,可让您快速一目了然地了解页面上发生的布局偏移的位置和时间。

如需在开发者工具中启用布局偏移区域,请依次前往设置 > 更多工具 > 渲染 > 布局偏移区域,然后刷新要调试的网页。布局偏移区域会以紫色短暂突出显示。

确定布局偏移原因的思路

无论布局偏移发生的时间或方式如何,您都可以按照以下步骤找出布局偏移的原因。您可以通过运行 Lighthouse 来补充这些步骤,但请注意,Lighthouse 只能识别在初始网页加载期间发生的布局偏移。此外,对于某些导致布局偏移的原因(例如,没有明确宽度和高度的图片元素),Lighthouse 也只能提供建议。

确定布局偏移的原因

布局偏移可能由以下事件引起:

  • DOM 元素位置的更改
  • DOM 元素的尺寸变化
  • 插入或移除 DOM 元素
  • 触发布局的动画

具体而言,最有可能“导致”布局偏移的元素是位于偏移元素前面的 DOM 元素。因此,在调查布局偏移发生的原因时,请考虑以下事项:

  • 前面的元素的位置或尺寸是否发生了变化?
  • 在被移位元素之前是否插入或移除了 DOM 元素?
  • 是否明确更改了移位元素的位置?

如果上一个元素未导致布局偏移,请继续考虑其他上一个元素和附近元素,以便继续搜索。

此外,布局偏移的方向和距离可以提供有关根本原因的提示。例如,向下偏移较大通常表示插入了 DOM 元素,而 1 像素或 2 像素的布局偏移通常表示应用了冲突的 CSS 样式,或者加载并应用了 Web 字体。

显示由字体切换导致的布局偏移的示意图
在此示例中,字体切换导致页面元素向上偏移了 5 像素。

以下是导致布局偏移事件的最常见的具体行为:

元素位置的更改(并非因其他元素移动而导致)

这类更改通常是以下原因导致的:

  • 延迟加载或覆盖之前声明的样式的样式表。
  • 动画和转场效果。

元素尺寸的更改

这类更改通常是以下原因导致的:

  • 较晚加载或覆盖之前声明的样式的样式表。
  • 不含 widthheight 属性的图片和 iframe,这些图片和 iframe 会在其“槽位”呈现后加载。
  • 不含 widthheight 属性的文本块会在文本呈现后切换字体。

插入或移除 DOM 元素

这通常是以下原因所致:

  • 插入广告和其他第三方嵌入内容。
  • 插入横幅、提醒和模态窗口。
  • 无限滚动和其他在现有内容上方加载更多内容的用户体验模式。

触发布局的动画

某些动画效果可以触发布局。一个常见的示例是,通过递增 topleft 等属性(而不是使用 CSS 的 transform 属性)来为 DOM 元素添加“动画效果”。如需了解详情,请参阅如何创建高性能 CSS 动画

重现布局偏移

您无法修复无法重现的布局偏移。若要更好地了解网站的布局稳定性,最简单但最有效的方法之一就是花 5-10 分钟与您的网站互动,以触发布局偏移。在此过程中,请保持控制台处于打开状态,并使用布局不稳定性 API 报告布局偏移。

对于难以定位的布局偏移,不妨考虑使用不同的设备和连接速度重复此练习。特别是,使用较慢的连接速度可以更轻松地识别布局偏移。此外,您还可以使用 debugger 语句,以便更轻松地逐步浏览布局转换。

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

最后,对于在开发过程中无法重现的布局问题,不妨考虑将布局不稳定性 API 与您选择的前端日志记录工具结合使用,以收集有关这些问题的更多信息。请参阅有关如何跟踪网页上移位幅度最大的元素的代码示例