延迟加载是一种将资源下载操作推迟到需要时再下载的技术,可以节省流量并减少关键资源的网络争用。它于2019年成为 Web 标准,今天大多数主流浏览器支持图片的 loading="lazy"
。
听起来不错,但是否存在延迟加载过多的情况?
这篇博文总结了我们如何分析公开的网络透明度数据和临时 A/B 测试,以了解原生图片延迟加载的采用率和性能特征。我们发现,延迟加载对于减少不需要的图片字节而言非常有效,但过度使用会对性能产生负面影响。具体而言,我们的分析表明,在初始视口中更加刻意地加载图片(而较为及时地加载其余图片),从而达到两全其美的效果:加载的字节数更少,并改善核心网页指标。
采用
根据 HTTP Archive 中的最新数据,17% 的网站使用了原生图片延迟加载,并且这种加载速度正在快速增长。对于相对较新的 API 来说,在生态系统中的这种立足点非常可观。
使用原生图片延迟加载的网站类型的细分数据。 (来源)
相关性效果
深入了解HTTP Archive 后,我们可以使用Largest Contentful Paint(LCP) 指标来比较使用原生图片延迟加载和不使用原生图片延迟加载的网页的性能。LCP 数据来自Chrome 用户体验报告 (CrUX) 中的真实用户体验,而非实验室中的合成测试。下图使用箱须图来直观呈现每个页面的 75 百分位 LCP 的分布情况:线表示第 10 和第 90 百分位,方框表示第 25 和第 75 百分位。
所有网页的 LCP 体验的第 75 百分位的分布情况,按是否使用原生图片延迟加载进行细分。 (来源)
未采用延迟加载的中位数网页的 LCP 第 75 百分位为 2,922 毫秒,而启用延迟加载的中位数网页的 LCP 为 3,546 毫秒。总体而言,使用延迟加载的网站的 LCP 性能往往更差。
请务必注意,这些结果是相关结果,并且不一定是延迟加载是导致性能下降的原因。假设,如果 WordPress 网站的速度往往有点慢,并且考虑到它们在延迟加载同类群组中的占比,就可以解释为什么会出现这种情况。因此,我们不妨仅关注 WordPress 网站,尽量避免这种差异。
WordPress 网页的第 75 百分位的 LCP 体验的分布情况,按是否使用原生图片延迟加载进行细分。 (来源)
遗憾的是,当我们深入研究 WordPress 页面时,出现了同样的情况;使用延迟加载的网页往往 LCP 性能较慢。未采用延迟加载的 WordPress 网页的中位数值为 3,495 毫秒,而启用延迟加载的中位数网页的 LCP 为 3,768 毫秒。
这仍不能证明延迟加载会导致页面运行速度变慢,但使用延迟加载确实与性能降低一致。为了尝试解答因果关系问题,我们设置了一个基于实验室的 A/B 测试。
因果关系效果
A/B 测试的目标是验证或反驳以下假设:如 WordPress 核心中所实现的原生图片延迟加载会降低 LCP 性能并减少图片字节数。使用的方法是使用 twentytwentyone 主题测试一个演示版 WordPress 网站。本文使用 WebPageTest 在桌面设备和模拟移动设备上测试了归档页面和单页类型(就像首页和文章页面一样)。我们测试了启用和未启用延迟加载的页面组合,并分别运行了 9 次测试,以获取 LCP 中位数值和图片字节数。
系列 | 默认 | 已停用 | 与默认值的差异 |
---|---|---|---|
twentytwentyone-archive-desktop | 2029 | 1759 | -13% |
twentytwentyone-archive-mobile | 1,657,000 | 1,403,000 | -15% |
twentytwentyone-single-desktop | 1655 | 1726 | 4% |
twentytwentyone-single-mobile | 1352 | 1384 | 2% |
上述结果比较了针对桌面设备和移动设备的归档网页和单个网页的测试的 LCP 中位数(以毫秒为单位)。我们发现,在归档页面上停用延迟加载后,LCP 有了显著的改善。但在单个网页上,这种差异更为中立。
值得注意的是,停用延迟加载的效果实际上似乎会使单页速度更快。不过,桌面设备和移动设备测试的 LCP 差异都小于 1 个标准差,因此我们将其归因于方差,并将总体变化视为中立。相比之下,存档网页的差值更像是两到三个标准差。
系列 | 默认 | 已停用 | 与默认值的差异 |
---|---|---|---|
twentytwentyone-archive-desktop | 577 | 1173 | 103% |
twentytwentyone-archive-mobile | 172 | 378 | 120% |
twentytwentyone-single-desktop | 301 | 850 | 183% |
twentytwentyone-single-mobile | 114 | 378 | 233% |
上述结果比较了每项测试的图片字节数中位数(以 KB 为单位)。不出所料,延迟加载对减少图片字节数有着非常明显的积极影响。如果真实用户将整个页面向下滚动,所有图片在进入视口时仍然会加载,但这些结果表明初始网页加载的性能得到了提升。
总结一下 A/B 测试的结果,WordPress 使用的延迟加载技术明显有助于减少图片字节数,但代价是延迟 LCP。
测试修正效果
在深入了解如何实现该修复之前,我们先来看看 WordPress 中延迟加载的工作原理。当前实现最重要的方面是,它会延迟加载首屏(视口内)的图片。CMS 博文承认这是应避免的模式,但当时的实验数据表明,对 LCP 的影响微乎其微,值得简化 WordPress 核心中的实现。
根据这些新数据,我们创建了一项实验性修复,以避免延迟加载首屏图片,并在与第一项 A/B 测试相同的条件下对其进行测试。
系列 | 默认 | 已停用 | fix | 与默认值的差异 | 与已停用的区别 |
---|---|---|---|---|---|
twentytwentyone-archive-desktop | 2029 | 1759 | 1749 | -14% | -1% |
twentytwentyone-archive-mobile | 1,657,000 | 1,403,000 | 1352 | -18% | -4% |
twentytwentyone-single-desktop | 1655 | 1726 | 1,676,000 | 1% | -3% |
twentytwentyone-single-mobile | 1352 | 1384 | 1342 | -1% | -3% |
这些结果充满希望。仅延迟加载非首屏图片会导致 LCP 回归完全逆转,甚至与完全停用 LCP 相比,可能还有细微的改进。怎么才能比不延迟加载更快呢?一种解释是,通过不加载非首屏图片,可以减少 LCP 图片的网络争用情况,从而加快加载速度。
系列 | 默认 | 已停用 | fix | 与默认值的差异 | 与已停用的区别 |
---|---|---|---|---|---|
twentytwentyone-archive-desktop | 577 | 1173 | 577 | 0% | -51% |
twentytwentyone-archive-mobile | 172 | 378 | 172 | 0% | -54% |
twentytwentyone-single-desktop | 301 | 850 | 301 | 0% | -65% |
twentytwentyone-single-mobile | 114 | 378 | 114 | 0% | -70% |
就图片字节数而言,与默认行为相比,此修复完全没有变化。这太棒了,因为这是当前方法的优势之一。
此修复存在一些注意事项。WordPress 会确定要在服务器端延迟加载哪些图片,也就是说,它不知道用户的视口大小,也不知道最初是否会在其中加载图片。因此,该修复会使用有关图片在标记中的相对位置的启发法来猜测图片是否会位于视口中。具体而言,如果图片是网页上的第一张精选图片或主要内容中的第一张图片,系统会假定它位于首屏(或靠近图片),并且不会延迟加载。页面级条件(例如标题中的字词数或主要内容早期的段落文本量)可能会影响图片是否在视口内。此外,还有一些用户级条件可能会影响启发词语的准确度,特别是视口大小和使用会改变页面滚动位置的锚点链接。出于这些原因,请务必承认,该修复只会经过校准以在一般情况下提供良好的性能,并且可能需要进行微调,以使这些结果适用于所有实际场景。
发布
既然已经确定了更好的延迟加载图片的方法,不仅减少了图片大小,而且提高了 LCP 性能,那么该如何让网站开始使用它呢?优先级最高的更改是向 WordPress Core 提交补丁,以实现实验性修复。
此外,还可以参考《适用于 CMS 的浏览器级延迟加载》这篇博文中的指南,以阐明首屏延迟加载的负面影响,以及 CMS 如何使用启发法来避免这种加载。
由于这些最佳实践适用于所有 Web 开发者,因此可能有必要在 Lighthouse 等工具中标记延迟加载反模式。如果您有兴趣了解该审核的进展情况,请参阅 GitHub 上的功能请求。在此之前,开发者可采取一项措施来查找被延迟加载的 LCP 元素实例,即向其字段数据添加更详细的日志记录。
new PerformanceObserver((list) => {
const latestEntry = list.getEntries().at(-1);
if (latestEntry?.element?.getAttribute('loading') == 'lazy') {
console.warn('Warning: LCP element was lazy loaded', latestEntry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
上面的 JavaScript 代码段将评估最新的 LCP 元素,并在该元素被延迟加载时记录警告。
这也凸显了延迟加载技术的尖端,以及在平台级别改进 API 的潜力。例如,Chromium 中有一个待解决的问题,需要尝试以原生方式快速加载前几张图片,这与修复方法类似(尽管具有 loading 属性)。
总结
如果您的网站使用原生图片延迟加载,请检查其实现方式并运行 A/B 测试,以便更好地了解其性能开销。若能更加刻意地加载首屏图片,则可能有所助益。如果您拥有 WordPress 网站,很可能会有一个补丁登陆 WordPress 核心。如果您使用的是其他 CMS,请确保其了解此处所述的潜在性能问题。
试用相对较新的 Web 平台 API 可能会带来风险和回报,它们被称之为前沿功能是有其原因的。虽然大家都已经开始感受到原生图片延迟加载的棘手问题,但也看到了使用这种加载方式的益处。