Web Performance

懒加载究竟会如何影响你的最大内容绘制

懒加载很有用,但它不是包治性能问题的通用修复。对于 LCP,它可能有帮助、可能有害,也可能没有影响,取决于被延迟的是哪一种资源。

The Wux Webtools Team The Wux Webtools Team 9 分钟阅读 人工智能辅助,人工审核
Illustration of a web performance timeline with a highlighted image request affecting LCP
目录
  1. 懒加载是一种调度决策,不是加速咒语
  2. 当你懒加载一张图片时,浏览器会做什么
  3. 简单规则:永远不要懒加载 LCP 候选元素
  4. 更正:使用实际的内部 URL
  5. 懒加载何时能改善 LCP
  6. LCP 图片的更好模式
  7. 背景图片需要额外谨慎
  8. JavaScript 懒加载往往会让情况更糟
  9. LCP 并不总是图片问题
  10. 如何测试懒加载变更而不欺骗自己
  11. 适用于大多数网站的实用策略

懒加载是一种调度决策,不是加速咒语

懒加载常被描述为一种性能改进。这个说法没错,就像不往行李箱里装东西确实能减重一样。它之所以有帮助,是因为浏览器在一开始要做的工作更少。

这个区别对 Largest Contentful Paint 很重要,通常简称为 LCP。LCP 衡量的是视口中最大的有意义元素何时完成渲染。在许多页面上,这个元素是主视觉图片。在另一些页面上,它可能是一个大标题、一张海报图、一张产品照片,或一个内容区块。

懒加载改变的是资源被请求的时间。它不会让图片解码更快,不会让服务器响应更快,也不会让字体更早渲染。如果你懒加载了错误的对象,尤其是最终成为 LCP 的元素,你其实是在告诉浏览器:在获取它必须展示、用来通过 Core Web Vitals 的那个关键资源之前先等一等。

这就是为什么懒加载既被过度使用,又被理解不足。

当你懒加载一张图片时,浏览器会做什么

原生图片懒加载通常这样添加:

<img src='hero.jpg' loading='lazy' alt='...'>

使用 loading='lazy' 时,浏览器可以推迟获取这张图片,直到它认为这张图片可能很快会被需要。在实践中,浏览器会使用它与视口的距离、网络状况、图片尺寸以及其他启发式规则。具体规则属于实现细节,并且可能变化。

使用 loading='eager',或者在大多数情况下不设置 lazy 属性时,浏览器会把这张图片视为正常加载流程的一部分。它仍然需要在 CSS、JavaScript、字体、图片和其他请求之间确定优先级,但这张图片会立即变得可发现。

这意味着懒加载主要影响三个阶段:

  • 发现: 浏览器何时注意到这个资源。
  • 请求开始: 网络获取何时开始。
  • 渲染时机: 资源最终何时可以被解码并绘制。

对于 LCP,危险的是请求开始。如果 LCP 图片请求开始得晚,之后的一切都会随之变晚。

简单规则:永远不要懒加载 LCP 候选元素

如果一张图片在初始视口中可见,并且很可能是最大的内容元素,不要懒加载它。

这包括:

  • 主视觉图片
  • 首屏以上的主要产品照片
  • 大尺寸文章导语图片
  • <img> 实现的类似背景的大图
  • 当海报图是主要视觉元素时的视频海报图片

浏览器只有在请求、传输、解码并绘制 LCP 图片之后,才能渲染它。懒加载会在第一步之前插入不确定性。即使很小的延迟,也可能足以让较慢连接上的 LCP 从可接受变成糟糕。

一种常见的失败模式如下:

  1. 服务器发送 HTML。
  2. 浏览器解析到一张首屏以上的图片。
  3. 图片带有 loading='lazy'
  4. 浏览器等待,因为懒加载启发式规则认为可以等待。
  5. CSS 和 JavaScript 继续加载。
  6. 图片请求比应有时间更晚才开始。
  7. LCP 变晚,即使图片文件本身已经做了合理优化。

这很令人沮丧,因为页面在代码审查中可能看起来很整洁。问题不只是文件大小,而是优先级。

如果你正在阅读实验室输出,并试图判断 LCP 是否真的是问题,我们关于如何在不慌张的情况下阅读 Lighthouse 报告的指南刻意写得很实用:在开始改代码之前,先区分字段数据、实验室提示和修复项。(注意:如果你的路由区分大小写,请使用 CMS 中的精确 URL。)

更正:使用实际的内部 URL

正确的 Wux 文章 URL 是 如何在不慌张的情况下阅读 Lighthouse 报告。核心观点不变:在改变加载行为之前,先识别 LCP 元素。

懒加载何时能改善 LCP

当懒加载让非关键资源不挡浏览器的路时,它可以间接改善 LCP。

想象一个产品页面,顶部有一张主视觉产品图,首屏以下有一个包含十二张推荐图片的轮播。如果十三张图片全部急切加载,浏览器可能会把带宽和连接槽用于用户还看不到的图片。在受限网络上,这可能会与主视觉图片、CSS 或字体文件竞争。

懒加载首屏以下的轮播图片,可以帮助 LCP 图片更早加载,因为初始页面加载期间参与竞争的非关键请求更少。

这才是懒加载真正合理的性能场景:

  • 急切加载首屏以上的 LCP 候选元素
  • 懒加载初始视口以下的图片
  • 避免使用沉重的脚本来延迟注入重要图片
  • 在 HTML 中保留图片尺寸,以避免布局偏移

懒加载本身不是 LCP 优化。它是一种资源优先级工具。当它保护关键路径时,它才有帮助。

LCP 图片的更好模式

对于首屏以上的 LCP 图片,目标是让浏览器早发现、早请求,并在没有布局不稳定的情况下渲染它。

一个可靠的基线如下:

<img
  src='/images/product-hero.avif'
  srcset='/images/product-hero-800.avif 800w, /images/product-hero-1400.avif 1400w'
  sizes='(max-width: 768px) 100vw, 720px'
  width='1400'
  height='900'
  loading='eager'
  fetchpriority='high'
  decoding='async'
  alt='Black hiking backpack with roll-top closure'
>

重要部分并不是装饰:

  • loading='eager' 防止懒加载延迟。
  • fetchpriority='high' 告诉浏览器这张图片很重要。
  • widthheight 预留空间并减少布局偏移。
  • srcsetsizes 防止下载过大的资源。
  • 在谨慎使用时,现代格式可以减少传输时间。

如果你仍然向每种屏幕提供同一张大 JPEG,那么图片格式和响应式尺寸可能比 lazy-loading 属性更重要。关于实用的决策树,请参阅 AVIF 何时胜过 WebP,何时不会

背景图片需要额外谨慎

CSS 背景图片不像普通 HTML 图片那样早被发现。浏览器必须先获取并解析 CSS,才知道它们的存在。如果你的 LCP 元素是一张 CSS 背景图片,你已经让发现过程变得更困难了。

这并不意味着背景图片被禁止使用。它意味着你应该有意为之。

对于装饰性图片,CSS 背景没有问题。对于有意义的主视觉图片,<img><picture> 元素通常更好,因为它对 HTML 解析器可见,支持 alt 文本,并且能很好地配合响应式图片属性。

如果你必须为 LCP 图片使用 CSS 背景,可以考虑预加载它:

<link rel='preload' as='image' href='/images/hero.avif'>

预加载也不是魔法棒。预加载过多图片,会以另一种形式制造同样的优先级问题。只把它用于真正重要的那一张图片,而不是设计系统里的每一张图片。

JavaScript 懒加载往往会让情况更糟

在原生懒加载获得广泛支持之前,许多网站使用 JavaScript 库,在页面加载后或 intersection observer 触发后,把 data-src 替换到 src。有些网站现在仍然如此。

对于长文章页面或图片密集型图库,这可能是合理的。但对于首屏以上内容,这是一个糟糕选择。

浏览器的预加载扫描器很快,但如果图片 URL 被藏在自定义属性中,它就无法请求这张图片,直到 JavaScript 运行。如果你的主视觉图片一开始是 data-src='hero.jpg',你就把发现过程推迟到了脚本下载、解析、执行和框架 hydration 之后。

这对 LCP 来说是很差的取舍。把关键图片 URL 放在真实的 HTML 中。让浏览器完成它该做的事。

LCP 并不总是图片问题

在某些页面上,LCP 元素是文本。在这种情况下,懒加载图片可能几乎没有直接影响。你的瓶颈可能是阻塞渲染的 CSS、缓慢的服务器响应、客户端渲染,或 Web 字体。

字体值得单独提出来,因为它们经常是导致文本渲染变晚的隐藏原因。一个大标题可能成为 LCP,而字体加载行为可能会延迟或改变这个标题的绘制时机。如果你的图片优化没有推动指标变化,请直接检查 LCP 元素,而不是做假设。我们关于 Web 字体仍然是大多数网站上最容易获得的性能收益 的文章介绍了那些无聊但常常有效的修复:更少字重、现代格式、合理的回退字体。

如何测试懒加载变更而不欺骗自己

不要通过在办公室 Wi-Fi 上盯着页面看来自测。你需要看到请求时序。

使用这个工作流:

  1. 打开 Chrome DevTools 并记录一段 Performance trace。
  2. 启用网络节流,例如 Fast 4G 或 Slow 4G。
  3. 在禁用缓存的情况下重新加载页面。
  4. 找到 LCP 标记。
  5. 识别 LCP 元素。
  6. 在 Network 面板中,检查该资源何时开始加载。

如果 LCP 资源开始得很晚,问问为什么:

  • 它被懒加载了吗?
  • 它是由 JavaScript 注入的吗?
  • 它藏在 CSS 里了吗?
  • 它被排在其他图片之后而降低了优先级吗?
  • 服务器响应很慢吗?

然后只做一个改动并重新测试。当团队在同一次部署中同时改变图片格式、懒加载、预加载、JavaScript bundle 和 CDN 设置时,性能工作会变得混乱。你也许能改善页面,但不会知道是哪一项改动起了作用。

字段数据也很重要。实验室工具对诊断很有用,但 LCP 会因设备、网络、视口、缓存状态和地理位置而变化。可以的话,使用真实用户监控或 Chrome User Experience Report 数据。

<!-- tool-cta:start -->

💡 试试这个: 通过 Image Compressor 处理你的 LCP 图像,使其保持较小并优先加载,从而无需 lazy loading 也能快速渲染。

<!-- tool-cta:end -->

适用于大多数网站的实用策略

对于大多数营销网站、电商页面、文档站点和出版类页面,这个策略已经足够:

  • 首屏以上的主要图片:急切加载,考虑高 fetch priority。
  • 首屏以下的内容图片:懒加载。
  • 图标和很小的 UI 资源:通常不值得逐个考虑。
  • CSS 背景主视觉:重新考虑改为 HTML 图片,或谨慎预加载。
  • JavaScript 注入的主视觉图片:如果可能,修复渲染架构。
  • 轮播:只急切加载第一张可见幻灯片;其余懒加载。

确实存在边缘情况。浏览器启发式规则在改进。框架会添加自动图片组件。一些平台现在会避免对检测到靠近视口的图片进行懒加载。尽管如此,原则并没有变:关键资源应该早且明显;非关键资源应该等待。

当懒加载表达了这种区别时,它是有价值的。当它把最重要的内容藏起来,直到页面已经开始输掉 LCP 竞赛之后才让浏览器看到时,它就是有害的。

常见问题

我应该在主视觉图片上使用 loading='lazy' 吗?
几乎不应该。如果主视觉图片在初始视口中可见,它很可能影响 LCP,应该急切加载。
懒加载会改善 Core Web Vitals 吗?
有可能,但通常是间接改善。懒加载首屏以下的图片可能减少早期网络竞争,并帮助 LCP。懒加载 LCP 图片通常会让 LCP 变差。
fetchpriority='high' 能替代急切加载吗?
不能。它应作为重要图片的额外提示使用。浏览器仍然需要尽早发现资源,而且图片不应该被藏在懒加载或 JavaScript 后面。
如果我的 LCP 元素是文本,而不是图片呢?
那么懒加载图片可能不会显著改变 LCP。请查看服务器响应时间、阻塞渲染的 CSS、客户端渲染和 Web 字体行为。
每一张首屏以下图片都应该懒加载吗?
通常是,尤其是在长页面上。例外情况是那些很可能马上进入视口,或对布局关键交互有必要的图片。

来源与进一步阅读

  1. web.dev: Browser-level image lazy loading for the web
  2. web.dev: Optimize Largest Contentful Paint
  3. MDN Web Docs: Lazy loading
  4. Chrome Developers: Optimize resource loading with the Fetch Priority API
关于作者
The Wux Webtools Team

最后更新:

继续阅读