由于在 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!">
您应该关注此标记的三个相关部分:
-
class
属性,这是您将在 JavaScript 中选择元素时使用的属性。 - 的
src
属性,它引用时会出现第一次加载页面的占位符图像。 - 在
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 forloading="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中的图像
虽然标签是在网页上使用图像的最常见方式,但也可以通过 CSSbackground-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 开发应用程序的人提供了一种熟悉的延迟加载图像的方法。