延迟加载图片和 <iframe> 元素

与其他类型的资源相比,图片和 <iframe> 元素通常会消耗更多带宽。对于 <iframe> 元素,加载和呈现其中的页面可能需要花费大量额外的处理时间。

对于延迟加载图片,推迟初始视口之外的图片的加载有助于减少对初始视口内更关键资源的带宽争用。在某些网络连接不佳的情况下,这可以改善网页的 Largest Contentful Paint (LCP),并且重新分配的带宽有助于 LCP 候选项更快地加载和绘制。

对于 <iframe> 元素,可以通过延迟加载这些元素来提高页面的 Interaction to Next Paint (INP) 在启动期间的效果。这是因为 <iframe> 是一个完全独立的 HTML 文档,具有自己的子资源。虽然 <iframe> 元素可以在单独的进程中运行,但与其他线程共享进程的情况并不少见,这可能会导致页面对用户输入的响应速度变慢。

因此,推迟屏幕外图片和 <iframe> 元素的加载是一项值得追求的技术,只需付出很少的努力,就能在性能方面获得相当不错的回报。本单元将介绍如何延迟加载这两种元素,以便在网页的关键启动期间提供更快、更好的用户体验。

使用 loading 属性延迟加载图片

您可以将 loading 属性添加到 <img> 元素,以告知浏览器应如何加载这些元素:

  • "eager" 会通知浏览器应立即加载图片,即使图片位于初始视口之外也是如此。这也是 loading 属性的默认值。
  • "lazy" 会延迟加载图片,直到图片距离可见视口的距离不超过设定的距离。此距离因浏览器而异,但通常设置得足够大,以便在用户滚动到图片时图片已加载完毕。

另请注意,如果您使用的是 <picture> 元素,则 loading 属性仍应应用于其子 <img> 元素,而不是 <picture> 元素本身。这是因为 <picture> 元素是一个容器,其中包含指向不同候选图片的其他 <source> 元素,并且浏览器选择的候选图片会直接应用于其子 <img> 元素。

请勿延迟加载初始视口中的图片

您应仅向位于初始视口之外的 <img> 元素添加 loading="lazy" 属性。不过,在网页呈现之前,要知道元素在视口中的相对确切位置可能很复杂。必须考虑不同的视口大小、宽高比和设备。

例如,桌面设备的视口可能与手机上的视口完全不同,因为它会呈现更多垂直空间,因此可能能够在初始视口中容纳在体积较小的设备的初始视口中无法显示的图片。在纵向模式下使用的平板电脑也显示了大量的垂直空间,可能比某些桌面设备还要多。

不过,在某些情况下,您应该明确避免应用 loading="lazy"。例如,在主打图片或其他图片用例(<img> 元素可能会显示在任何设备上的折叠线上方或布局顶部附近)中,您绝对应从 <img> 元素中省略 loading="lazy" 属性。对于可能成为 LCP 候选图片,这一点尤为重要

延迟加载的图片需要等待浏览器完成布局,以便确定图片的最终位置是否在视口内。这意味着,如果可见视口中的 <img> 元素具有 loading="lazy" 属性,则系统仅会在所有 CSS 下载、解析并应用到网页后请求该属性,而不是在预加载扫描器在原始标记中发现该属性后立即提取该属性。

由于所有主要浏览器都支持 <img> 元素上的 loading 属性,因此无需使用 JavaScript 来延迟加载图片,因为向网页添加额外的 JavaScript 来提供浏览器已提供的功能会影响网页性能的其他方面,例如 INP。

图片延迟加载演示

延迟加载 <iframe> 元素

延迟加载 <iframe> 元素,直到它们在视口中可见,可以节省大量数据,并改进顶级页面加载所需的关键资源的加载速度。此外,由于 <iframe> 元素本质上是在顶级文档中加载的整个 HTML 文档,因此它们可以包含大量子资源(尤其是 JavaScript),如果这些框架中的任务需要大量处理时间,则可能会显著影响网页的 INP。

第三方嵌入是 <iframe> 元素的常见用例。例如,嵌入式视频播放器或社交媒体帖子通常使用 <iframe> 元素,并且通常需要大量子资源,这也可能会导致顶级网页资源的带宽争用。例如,延迟加载 YouTube 视频的嵌入内容可在初始网页加载期间节省超过 500 KiB,而延迟加载 Facebook “赞”按钮插件可节省超过 200 KiB,其中大部分是 JavaScript。

无论哪种方式,每当您在网页上有折叠线下方的 <iframe> 时,如果前期加载它不是必不可少的,您都应强烈考虑延迟加载它,因为这样做可以显著改善用户体验。

<iframe> 元素的 loading 属性

所有主要浏览器还支持 <iframe> 元素上的 loading 属性loading 属性的值及其行为与使用 loading 属性的 <img> 元素相同:

  • "eager" 为默认值。它会通知浏览器立即加载 <iframe> 元素的 HTML 及其子资源。
  • "lazy" 会延迟加载 <iframe> 元素的 HTML 及其子资源,直到其距离视口的距离不超过预定义的距离。

延迟加载 iframe 演示

外墙

您可以根据用户互动情况按需加载嵌入内容,而不是在网页加载期间立即加载。为此,您可以显示图片或其他适当的 HTML 元素,直到用户与其互动。用户与该元素互动后,您可以将其替换为第三方嵌入内容。这种技术称为“外观”。

外观的常见用例是第三方服务中的视频嵌入,其中嵌入可能涉及加载视频内容本身之外的许多其他可能昂贵的子资源(例如 JavaScript)。在这种情况下,除非有合理的需求需要视频自动播放,否则嵌入的视频需要用户点击播放按钮与其互动,然后才能播放。

这是展示与视频嵌入内容视觉上相似的静态图片的绝佳机会,并且在此过程中可以节省大量带宽。用户点击图片后,该图片会被实际的 <iframe> 嵌入内容替换,这会触发第三方 <iframe> 元素的 HTML 及其子资源开始下载。

除了改进初始网页加载速度之外,另一个主要优势是,如果用户从未播放视频,系统就不会下载传送视频所需的资源。这是一种很好的模式,因为它可确保用户仅下载他们实际需要的内容,而不会对用户的需求做出可能有误的假设。

聊天 widget 是外观技术的另一个绝佳用例。大多数聊天 widget 都会下载大量 JavaScript,这可能会对网页加载速度和对用户输入的响应速度产生不利影响。与预加载任何内容一样,系统会在加载时产生费用,但对于聊天 widget,并非所有用户都不会与其互动。

另一方面,借助外观,您可以将第三方“开始聊天”按钮替换为虚构按钮。当用户与该 widget 进行有意义的互动(例如将指针悬停在其上合理的时间,或点击该 widget)后,系统会在用户需要时将实际的功能性聊天 widget 插入到相应位置。

虽然您当然可以自行构建外观,但对于更受欢迎的第三方,也有可用的开源选项,例如,适用于 YouTube 视频的 lite-youtube-embed、适用于 Vimeo 视频的 lite-vimeo-embed,以及适用于聊天 widget 的 React Live Chat Loader

JavaScript 延迟加载库

如果您需要延迟加载 <video> 元素、<video> 元素 poster 图片、通过 CSS background-image 属性加载的图片或其他不受支持的元素,可以使用基于 JavaScript 的延迟加载解决方案(例如 lazysizesyall.js),因为延迟加载此类资源不是浏览器级功能。

特别是,自动播放和循环播放无音轨的 <video> 元素比使用动画 GIF 更高效,因为 GIF 的大小通常是同等视觉质量的视频资源的几倍。即便如此,这些视频在带宽方面仍然可能占用大量资源,因此延迟加载这些视频是一项额外的优化措施,可以大大减少带宽浪费。

大多数此类库都使用 Intersection Observer API(如果页面的 HTML 在初始加载后发生更改,还会使用 Mutation Observer API)来识别元素何时进入用户的视口。如果图片可见(或接近视口),则 JavaScript 库会将非标准属性(通常为 data-src 或类似属性)替换为正确的属性,例如 src

假设您有一个视频要替换动画 GIF,但您想使用 JavaScript 解决方案延迟加载该视频。您可以使用 yall.js 实现此目的,具体方法是使用以下标记模式:

<!-- The autoplay, loop, muted, and playsinline attributes are to
     ensure the video can autoplay without user intervention. -->
<video class="lazy" autoplay loop muted playsinline width="320" height="480">
  <source data-src="video.webm" type="video/webm">
  <source data-src="video.mp4" type="video/mp4">
</video>

默认情况下,yall.js 会监控类为 "lazy" 的所有符合条件的 HTML 元素。在页面上加载并执行 yall.js 后,系统不会加载视频,直到用户将其滚动到视口中。此时,<video> 元素的子 <source> 元素上的 data-src 属性会换成 src 属性,后者会发出下载视频的请求并自动开始播放视频。

知识测验

<img><iframe> 元素的 loading 属性的默认值是什么?

"eager"
正确!
"lazy"
请重试。

何时适合使用基于 JavaScript 的延迟加载解决方案?

对于任何可以延迟加载的资源。
请重试。
对于不支持 loading 属性的资源,例如旨在替换动画图片或延迟加载 <video> 元素的海报图片的自动播放视频。
正确!

何时可以使用外观?

对于会消耗大量数据的任何第三方嵌入内容,无论用户是否有此需求。
请重试。
对于任何第三方嵌入内容,如果其加载所需的资源不仅数量巨大,而且很有可能不是所有用户都与其互动,
正确!

后续内容:预提取和预渲染

现在,您已经掌握了如何延迟加载图片和 <iframe> 元素,可以确保在满足用户需求的同时,加快网页加载速度。不过,在某些情况下,推测性加载资源可能是可取的做法。在下一个模块中,了解预提取和预渲染,以及这些技术如何在谨慎使用时通过提前加载后续网页来显著加快导航速度。