解决布局不稳定问题

有关如何使用 WebPageTest 识别和修复布局不稳定性问题的演示。

在之前的一篇博文中,我介绍了如何在 WebPageTest 中衡量累积布局偏移 (CLS)。CLS 是所有布局偏移的汇总,因此在这篇文章中,我想深入了解并检查网页上的每个布局偏移,以尝试了解可能导致不稳定的原因,并实际尝试解决问题。

衡量布局偏移

使用 Layout Instability API,我们可以获取网页上所有布局偏移事件的列表:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

这会生成一个不以输入事件开头的布局偏移数组:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

在此示例中,210 毫秒时出现了一次非常小的 0.01% 的偏移。

了解转变的时间和严重程度有助于缩小可能导致转变的原因范围。让我们回到 WebPageTest,在实验室环境中进行更多测试。

在 WebPageTest 中衡量布局偏移

与在 WebPageTest 中衡量 CLS 类似,衡量单个布局偏移需要使用自定义指标。幸运的是,现在 Chrome 77 已稳定,该流程也变得更简单了。布局不稳定性 API 默认处于启用状态,因此您应该能够在 Chrome 77 中的任何网站上执行该 JS 代码段,并立即获得结果。在 WebPageTest 中,您可以使用默认的 Chrome 浏览器,而不必担心命令行标志或使用 Canary。

因此,我们来修改该脚本,以生成 WebPageTest 的自定义指标:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

此脚本中的 promise 会解析为数组的 JSON 表示形式,而不是数组本身。这是因为自定义指标只能生成字符串或数字等基本数据类型。

我将用于测试的网站是 ismyhostfastyet.com,这是我构建的一个用于比较网络托管服务商实际加载性能的网站。

确定布局不稳定的原因

结果中,我们可以看到 LayoutShifts 自定义指标具有以下值:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

总而言之,在 3087 毫秒时发生了一次 34.2% 的布局偏移。为了帮助找出问题,我们来使用 WebPageTest 的影片条视图

胶片状图片中的两个单元格,显示布局偏移前后的屏幕截图。
幻灯片中的两个单元格,显示布局偏移前后的屏幕截图。

在影片轨道中滚动到大约 3 秒标记处,我们可以清楚地看到 34% 的布局偏移是由彩色表格造成的。该网站会异步提取 JSON 文件,然后将其渲染到表格中。该表格最初是空的,因此在加载结果时等待填充该表格会导致出现这种偏移。

网页字体标题突然出现。
网页字体标题莫名其妙地出现。

但还不止这些。当页面在约 4.3 秒时视觉上完全呈现时,我们可以看到页面“Is my host fast yet?”的 <h1> 突然出现。这是因为网站使用了 Web 字体,但未采取任何措施来优化渲染。发生这种情况时,布局实际上不会发生变化,但用户必须等待这么长时间才能阅读标题,这仍然会带来糟糕的用户体验。

修复布局不稳定性

现在,我们知道异步生成的表格会导致视口移动三分之一,是时候修复此问题了。在实际加载 JSON 结果之前,我们不知道表格的内容,但我们仍然可以使用某种占位数据来填充表格,以便在渲染 DOM 时布局本身相对稳定。

以下是用于生成占位数据的代码:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

占位数据在排序之前是随机生成的。它包含重复随机次数的“█”字符,用于为文本创建视觉占位符,并包含随机生成的三种主要值的分布。我还添加了一些样式,用于将表格中的所有颜色去饱和,以便清楚地表明数据尚未完全加载。

您使用的占位符的外观对布局稳定性没有影响。占位符的目的是向用户保证内容即将显示,并且网页没有损坏。

以下是加载 JSON 数据时占位符的显示效果:

系统会使用占位数据呈现数据表。
系统会使用占位数据呈现数据表。

解决网页字体问题要简单得多。由于该网站使用的是 Google 字体,因此我们只需在 CSS 请求中传入 display=swap 属性即可。就这些了。Fonts API 将在字体声明中添加 font-display: swap 样式,使浏览器能够立即以回退字体渲染文本。以下是包含相应修复的标记:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

验证优化

通过 WebPageTest 重新运行网页后,我们可以生成前后对比,直观呈现差异并衡量新的布局不稳定性程度:

WebPageTest 胶片显示了两个网站在有布局优化和没有布局优化的情况下并排加载。
WebPageTest 胶片显示了两个网站在有布局优化和没有布局优化的情况下并排加载。
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

根据此自定义指标,在 3071 毫秒时(与之前的时间大致相同)仍然发生了布局偏移,但偏移的严重程度要小得多:0.005%。我可以接受。

从胶片中还可以清楚地看出,<h1> 字体会立即回退到系统字体,从而让用户能够更快地阅读内容。

总结

复杂的网站可能会比此示例中发生更多的布局偏移,但补救过程仍然相同:将布局不稳定性指标添加到 WebPageTest,将结果与直观的加载胶片带进行交叉引用,以找出问题所在,然后使用占位符预留屏幕空间,从而实现修复。

(还有一件事)衡量真实用户遇到的布局不稳定性

能够在优化前后对网页运行 WebPageTest 并看到指标有所改进固然不错,但真正重要的是用户体验确实有所提升。难道这不是我们最初尝试改进网站的原因吗?

因此,如果我们在衡量传统 Web 性能指标的同时,开始衡量真实用户的布局不稳定性体验,那就太棒了。这是优化反馈环的关键环节,因为有了现场数据,我们才能知道问题出在哪里,以及我们的修复是否带来了积极的变化。

除了收集您自己的布局不稳定性数据之外,您还可以查看 Chrome 用户体验报告,其中包含数百万个网站上真实用户体验的累积布局偏移数据。借助该工具,您可以了解自己(或竞争对手)的表现,也可以使用它来探索整个网络中的布局不稳定性状态。