由于在 HTML 中作为元素或 CSS 背景图像内联,图像可以出现在网页上。在这篇文章中,您将了解如何延迟加载这两种类型的图像。

内嵌图像

最常见的延迟加载候选是元素中使用的图像。对于内嵌图像,我们有三个延迟加载选项,可以组合使用以实现跨浏览器的最佳兼容性:

  • 使用浏览器级延迟加载
  • 使用交叉点观察器
  • 使用滚动和调整大小事件处理程序

使用浏览器级别的延迟加载

Chrome 和 Firefox 都支持带有​​loading​​​属性的延迟加载。此属性可以添加到元素,也可以添加到元素。值​​lazy​​告诉浏览器如果图像在视口中则立即加载图像,并在用户滚动到其他图像附近时获取其他图像。



注意目前是非标准的。虽然在 Chromium 中实现,但它还没有规范,并且在发生这种情况时可能会在未来发生变化。我们建议不要使用该​​loading​​属性延迟加载 iframe,直到它成为规范的一部分。



有关​​浏览​​​器支持的详细信息,请参阅​​loading​​​MDN 的​​浏览器兼容性​​表字段。如果浏览器不支持延迟加载,则该属性将被忽略,图像将像往常一样立即加载。

对于大多数网站而言,将此属性添加到内嵌图像将提高性能并节省用户加载他们可能永远不会滚动到的图像。如果您有大量图像并希望确保不支持延迟加载的浏览器用户受益,您需要将其与下面解释的方法之一结合起来。

使用交叉点观察器

为了填充元素的延迟加载,我们使用 JavaScript 来检查它们是否在视口中。如果是,它们的​​src​​​(有时是​​srcset​​)属性将填充到所需图像内容的 URL。

如果您以前编写过延迟加载代码,那么您可能已经通过使用诸如​​scroll​​​或 之类的事件处理程序来完成您的任务​​resize​​​。虽然这种方法在浏览器间最兼容,但现代浏览器提供了一种更高效、更有效的方法来通过​​Intersection Observer API​​来完成检查元素可见性的工作。



并非所有浏览器都支持 Intersection Observer,特别是 IE11 及更低版本。



相较于依赖各种事件处理程序的代码,Intersection Observer 更易于使用和阅读,因为您只需注册一个观察者即可观察元素,而无需编写繁琐的元素可见性检测代码。剩下要做的就是决定当元素可见时要做什么。让我们为延迟加载的元素假设这个基本的标记模式:

<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-src​​​和​​data-srcset​​属性,这是包含一旦元素中视,你会加载图像的URL占位符属性。

现在让我们看看如何在 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​​​。如果 Intersection Observer 可用,创建一个新的观察者,当​​img.lazy​​元素进入视口时运行回调。



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

使用事件处理程序来支持 Internet Explorer 

虽然您应该使用 Intersection Observer 进行延迟加载,但您的应用程序要求可能是浏览器兼容性至关重要。​​您可以polyfill Intersection Observer 支持​​​(这将是最简单的),但您也可以使用, 和可能的事件处理程序回退到代码​​scroll​​,以确定元素是否在视口中。

假设与之前相同的标记模式,此 Glitch 示例​​getBoundingClientRect​​​在​​scroll​​​事件处理程序中使用以检查是否有任何​​img.lazy​​​元素在视口中。甲​​setTimeout​​​调用用于延迟处理,和一个​​active​​变量包含其用于节流函数调用的处理的状态。由于图像是延迟加载的,它们会从元素数组中删除。当元素数组达到 长度为 0时,将删除滚动事件处理程序代码。



虽然这段代码几乎适用于任何浏览器,但它存在潜在的性能问题,因为重复​​setTimeout​​​调用可能会造成浪费,即使其中的代码受到限制。在此示例中,无论视口中是否有图像,都会在文档滚动或窗口大小调整时每 200 毫秒运行一次检查。此外,跟踪有多少元素需要延迟加载和取消绑定滚动事件处理程序的繁琐工作留给了开发人员。您可以在​​The Complete Guide to Lazy Loading Images 中​​找到有关此技术的更多信息。

简单地说:尽可能使用浏览器级延迟加载和后备 Intersection Observer 实现,并且仅在尽可能广泛的兼容性是关键应用程序要求时才使用事件处理程序。

CSS中的图像

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

与不考虑可见性而加载的元素不同,CSS 中的图像加载行为是通过更多推测来完成的。当​​文件和CSS对象模型​​​和​​渲染树​​是建立,浏览器探讨如何CSS请求外部资源之前应用于文档。如果浏览器确定涉及外部资源的 CSS 规则不适用于当前构造的文档,则浏览器不会请求它。

这种推测行为可用于通过使用 JavaScript 来确定元素何时位于视口内,然后将一个类应用到该元素,该类应用样式调用背景图像,从而延迟 CSS 中的图像加载。这会导致在需要时而不是在初始加载时下载图像。例如,让我们以一个包含大英雄背景图片的元素为例:

<div class="lazy-background">
<a href="/buy-a-thing">你好</a>
</div>

该​​div.lazy-background​​​元素通常包含由某些 CSS 调用的英雄背景图像。但是,在这个延迟加载示例中,您可以通过在视口中添加到元素的类来隔离​​div.lazy-background​​​元素的​​background-image​​​属性​​visible​​:

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

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

从这里开始,使用 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);
});
}
});



如前所述,如果您需要 Internet Explorer 支持延迟加载背景图像,您将需要填充 Intersection Observer 代码,因为该浏览器缺乏支持。

延迟加载库

以下库可用于延迟加载图像。

  • ​lazysizes​​​是一个功能齐全的延迟加载库,可以延迟加载图像和 iframe。它使用的模式与此处显示的代码示例非常相似,因为它自动绑定到元素上的​​lazyload​​​类,并要求您在​​data-src​​​和/或​​data-srcset​​​属性中指定图像 URL ,其内容分别交换到​​src​​​和/或​​srcset​​​属性中. 它使用 Intersection Observer(您可以对其进行 polyfill),并且可以使用​​许多插件​​进行扩展以执行诸如延迟加载视频之类的操作。
  • ​vanilla-lazyload​​是用于延迟加载图像、背景图像、视频、iframe 和脚本的轻量级选项。它利用 Intersection Observer,支持响应式图像,并启用浏览器级别的延迟加载。
  • ​lozad.js​​是另一个仅使用 Intersection Observer 的轻量级选项。因此,它具有很高的性能,但需要先进行 polyfill,然后才能在较旧的浏览器上使用它。
  • ​yall.js​​是一个使用 Intersection Observer 并回退到事件处理程序的库。它与 IE11 和主要浏览器兼容。
  • 如果您需要特定于 React 的延迟加载库,请考虑​​react-lazyload​​。虽然它不使用 Intersection Observer,但它确实为那些习惯于使用 React 开发应用程序的人提供了一种熟悉的延迟加载图像的方法。