延迟加载图片

由于图片作为 <img> 元素内嵌在 HTML 中,因此可以显示在网页上 或 CSS 背景图片在本博文中,您将了解如何延迟加载这两种类型的图片。

内嵌图片

最常见的延迟加载对象是 <img> 元素中使用的图片。 对于内嵌图片,我们有三种延迟加载选项 以下这些方法可以组合使用,以实现各种浏览器的最佳兼容性:

使用浏览器级延迟加载

Chrome 和 Firefox 都支持使用 loading 属性进行延迟加载。 此属性可添加到 <img> 元素以及 <iframe> 元素。 如果值为 lazy,则指示浏览器在图片位于视口中时立即加载该图片。 以及在用户滚动至其他图片时获取这些图片。

请参阅 MDN 的 loading 字段 浏览器兼容性 表。 如果浏览器不支持延迟加载,该属性将被忽略 并且图片会立即照常加载

对于大多数网站,向内嵌图片添加此属性可提升性能 并节省用户加载他们可能永远不会滚动到的图片。 如果您有大量图片,并且想确保浏览器用户不支持延迟加载, 则需要将其与下面介绍的某个方法结合使用。

如需了解详情,请参阅适用于网页的浏览器级延迟加载

使用 Intersection Observer

为了 polyfill 延迟加载 <img> 元素,我们使用 JavaScript 检查这些元素是否在 视口如果是,则其 src(有时是 srcset)属性为 填充为所需图片内容的网址。

如果您之前编写过延迟加载代码,那么您可能已经完成了任务 使用 scrollresize 等事件处理脚本。虽然这种方法是 最兼容的所有浏览器,但现代浏览器可提供性能更佳、 通过 Intersection Observer API

与依赖于各种不同技术的代码相比,Intersection Observer 更易于使用和阅读 因为您只需注册一个观察器即可监控 而无需编写冗长的元素可见性检测代码。全部 剩下要做的就是确定元素可见时该如何操作。 我们假设您的 <img> 元素延迟加载了以下基本标记模式:

<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">

您应重点关注此标记的三个相关部分:

  1. class 属性,即您在选择元素时要使用的属性 JavaScript。
  2. src 属性,用于引用 。
  3. data-srcdata-srcset 属性是占位符属性 ,其中包含元素进入视口后要加载的图片的网址。

现在,我们来看看如何在 JavaScript 中使用 Intersection Observer 进行延迟加载 使用此标记格式的图片:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to event handlers here
  }
});

在文档的 DOMContentLoaded 事件中,此脚本会向 DOM 查询所有 类为 lazy<img> 元素。如果有 Intersection Observer, 创建一个新的观察器,以在 img.lazy 元素进入 视口

Intersection Observer 适用于所有现代浏览器。 因此,将其用作 loading="lazy" 的 polyfill 可确保大多数访问者都可以使用延迟加载。

CSS 中的图片

虽然 <img> 标记是在网页上使用图片的最常见方式,但图片 也可以通过 CSS 文件调用 background-image 属性(和其他属性)。浏览器级延迟加载不适用于 CSS 背景图片, 因此如果您有要延迟加载的背景图片,则需要考虑其他方法。

<img> 元素不同,该元素会随便加载, CSS 中的图片加载行为是通过更多 猜测。当文档和 CSS 对象 模型呈现 树 构建之后,浏览器会先检查 CSS 应用于文档的方式 请求外部资源如果浏览器确定了 CSS 规则 因为涉及外部资源的文档并不适用于当前文档, 浏览器不会请求它。

这种推测行为可用于延迟加载 CSS 中的图片, 使用 JavaScript 确定元素何时位于视口内,以及 随后将一个类应用到该元素,以应用调用 背景图片。这样可以在需要时下载图片 而不是在初始加载时加载例如,假设某个元素包含 大型主打背景图片:

<div class="lazy-background">
  <h1>Here's a hero heading to get your attention!</h1>
  <p>Here's hero copy to convince you to buy a thing!</p>
  <a href="/buy-a-thing">Buy a thing!</a>
</div>

div.lazy-background 元素通常包含主打背景 由某个 CSS 调用的图片。不过,在这个延迟加载示例中,您可以 div.lazy-background 元素的 background-image 属性(通过 visible) 类:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

接着,使用 JavaScript 检查元素是否在视口中(使用 Intersection Observer!),并将 visible 类添加到 div.lazy-background 元素,用于加载图片:

document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

对 Largest Contentful Paint (LCP) 的影响

延迟加载是一项很好的优化措施,可将图片的加载推迟到实际需要的时间,从而减少启动期间的整体流量消耗和网络争用。这可以缩短启动时间,并通过减少图像解码所需的时间来减少在主线程上的处理。

不过,如果您过于急于使用延迟加载技术,该技术可能会对您网站的 Largest Contentful Paint LCP 产生负面影响。您应避免在启动期间延迟加载视口中的图片。

使用基于 JavaScript 的延迟加载器时,您需要避免延迟加载视口内图片,因为这些解决方案通常使用 data-srcdata-srcset 属性作为 srcsrcset 属性的占位符。这里的问题在于,系统会延迟加载这些图片,因为浏览器预加载扫描器在启动期间找不到它们

即便是使用浏览器级延迟加载来延迟加载视口中的图片,也可能适得其反。对视口内图片应用 loading="lazy" 后,该图片会延迟到浏览器确定它位于视口内,这可能会影响网页的 LCP。

永不在启动期间延迟加载视口中可见的图片。这种模式会对您网站的 LCP 产生负面影响,进而对用户体验产生负面影响。如果启动时需要图片,请在启动时尽快加载,而不要延迟加载!

延迟加载库

您应该尽可能使用浏览器级延迟加载,但如果您发现自己无法采用此方法(例如有大量用户仍依赖于旧版浏览器),则可以使用以下库延迟加载图片:

  • lazysizes 是一个功能齐全的延迟视图 用于延迟加载图片和 iframe 的加载库。它使用的模式 它会自动绑定到 lazyload 类,并要求您指定在<img> data-src 和/或 data-srcset 属性,它们的内容交换 src 和/或 srcset 属性。使用交叉路口 Observer(可对其进行 polyfill 操作),并且可通过 插件 例如延迟加载视频详细了解如何使用 lazysizes
  • vanilla-lazyload 是一个 用于延迟加载图片、背景图片、视频、iframe 和脚本。它利用了 Intersection Observer,支持自适应图片,并且 支持浏览器级延迟加载
  • lozad.js 是另一个 选项。因此,它的性能非常出色 但需要先进行 polyfill 操作,然后才能在旧版浏览器上使用。
  • 如果您需要 React 专用的延迟加载库,请考虑 react-lazyload。虽然 未使用 Intersection Observer,它提供了一种熟悉的延迟方法, 为习惯于使用 React 开发应用的用户加载图片。