延迟加载图像 - 完整指南
如今,图片对于每个网站和应用程序都至关重要。无论是营销横幅、产品图片还是徽标,我们无法想象一个没有图片的网站。然而,遗憾的是,图片尺寸巨大,成为页面大小的最大贡献者。根据最新的HTTP 存档数据,桌面端的页面大小中位数为 1511 KB。图片占了其中的近 650 KB,约占页面总大小的 45%。既然我们无法摆脱图片,那么我们就需要让网页在图片的帮助下快速加载。在本指南中,我们将讨论延迟加载图片,这种技术有助于缩短页面加载时间并减小页面大小,同时仍保留页面上的所有图片。
快速浏览一下延迟加载实现的功能
在继续之前,这里有一个示例视频,演示了延迟加载的工作原理。请注意,当页面滚动时,灰色占位符会被实际图像替换。
什么是延迟加载图像?
延迟加载图像是指网页和应用程序开发中的一组技术,它将页面上的图像加载延迟到稍后(即真正需要这些图像时)进行,而不是预先加载。这些技术有助于提升性能、更好地利用设备资源并降低相关成本。
英语中的“懒惰”一词通常指尽可能逃避工作的行为。
类似地,延迟加载是指在页面上不需要资源时才加载它们。我们通常不会在页面加载完成后立即加载这些资源,而是将这些资源的加载推迟到真正需要它们的时候。
延迟加载技术几乎可以应用于页面上的所有资源。例如,在单页面应用中,如果某个 JS 文件稍后才需要,最好不要一开始就加载它。如果某个图片一开始不需要,那么最好等到真正需要时再加载。
在这里,我们将坚持延迟加载图像以及如何在您的网站上很好地做到这一点。
为什么要采用延迟加载图像?
延迟加载是指延迟加载页面上不需要立即加载的图片。如果图片在页面加载时用户不可见,则会在用户滚动页面并实际可见时加载。如果用户始终不滚动页面,则用户不可见的图片将永远不会被加载。
这有两个主要优点。
1. 性能改进
对于网站管理员来说,最重要的一点是提升性能和加载时间。使用延迟加载,您可以减少页面初始需要加载的图片数量。更少的资源请求意味着需要下载的字节数更少,从而减少对用户有限网络带宽的竞争。这确保了设备能够更快地下载和处理剩余资源。因此,与没有延迟加载的情况相比,页面可以更快地可用。
2.降低成本
第二个好处是交付成本方面。图片交付,或任何其他资产的交付,通常按传输的字节数收费。如前所述,使用延迟加载,如果图片不可见,则永远不会加载。因此,您可以减少页面上交付的总字节数。特别是对于那些跳出页面或仅与页面顶部交互的用户而言。从交付网络传输的字节数的减少可以降低交付成本。在接下来的章节中,我们将探讨延迟加载,这一点将更加明显。
哪些图片可以延迟加载?
延迟加载的基本思想很简单——延迟加载任何当前不需要的内容。对于图片来说,通常意味着任何用户无法直接看到的图片都可以延迟加载。当用户向下滚动页面时,图片占位符开始进入视口(网页的可见部分)。当这些图片可见时,我们触发它们的加载。
您可以使用Google Lighthouse 审核工具找出哪些图片适合延迟加载,以及在初始页面加载时可以节省多少字节。此工具执行的审核功能中有一个专门针对屏幕外图片的部分。除了页面上其他与图片相关的关键优化之外,您还可以使用ImageKit 的网站分析器来识别您的网站是否使用了延迟加载。
延迟加载不仅对良好的性能至关重要,而且对于提供良好的用户体验也至关重要。由于将性能和用户体验与延迟加载相结合至关重要且具有挑战性,因此在了解了不同的图片延迟加载方法之后,我们将在本指南中继续更详细地讨论这个主题。
图像的延迟加载技术
网页上的图片可以通过两种方式加载——使用标签或使用 CSS
background
属性。我们先来了解一下两者中更常见的一种——标签,然后再讨论 CSS 背景图片。
标签中延迟加载图像的一般概念
延迟加载图像可以分为两个步骤
第一步是防止图片提前加载。对于使用<img />
标签加载的图片,浏览器会使用src
标签的属性来触发图片加载。无论它是 HTML 中的第一张图片还是第一千张图片,并且距离屏幕很远,只要浏览器获取到该src
属性,就会触发图片加载。
因此,要延迟加载此类图像,请将图像 URL 放在 以外的属性中src
。假设我们在data-src
image 标签的属性中指定图像 URL。现在src
为空,浏览器不会触发图像加载
现在我们已经停止了预先加载,我们需要告诉浏览器何时加载图片。为此,我们会检查图片(即其占位符)是否进入视口,是否立即触发加载。检查图片何时进入视口有两种方法。让我们通过实际的代码示例来分别看看这两种方法。
使用 Javascript 事件触发图像加载
在这项技术中,我们使用滚动事件监听器resize
和orientationChange
浏览器事件。scroll 事件是用户滚动页面时需要检查的明显事件。resize 事件和 orientationChange 事件对于延迟加载同样重要。resize 事件发生在浏览器窗口大小发生变化时。orientationChange 事件在设备从横屏模式旋转为竖屏模式或从竖屏模式旋转为横屏模式时触发。在这种情况下,屏幕上可见的图片数量会发生变化。因此,我们需要触发这些图片的加载。
当上述任一事件发生时,我们会查找页面上所有需要延迟加载但尚未加载的图片。我们会检查这些图片中哪些图片现在位于视口中。具体操作是使用图片的顶部偏移量、当前文档滚动顶部和窗口高度。如果图片已进入视口,我们会从data-src
src 属性中获取 URL,并将其赋值给 src 属性。这将触发图片加载。我们还会移除 lazy 类,该类用于标识稍后触发事件的延迟加载图片。所有图片加载完成后,我们会移除事件监听器。
当我们滚动时,滚动事件会快速触发多次。因此,为了提高性能,我们添加了一个短暂的超时时间来限制延迟加载函数的执行。
以下是此方法的一个工作示例。
如果你注意到的话,示例中的前三张图片是预先加载的。URL 直接存在于 src 属性中,而不是 srcdata-src
属性中。这对于良好的用户体验至关重要。由于这些图片位于页面顶部,因此应尽快使其可见。我们不能等待事件或 JS 执行来加载它们。
使用 Intersection Observer API 触发图像加载
Intersection Observer API 是浏览器中一个相对较新的 API。它能够轻松检测元素何时进入视口,并在进入时执行相应操作。在之前的方法中,我们必须绑定事件,兼顾性能,并实现一种计算元素是否在视口内的方法。Intersection Observer API 简化了这一过程,避免了复杂的计算,并带来了卓越的性能。
下面是一个使用 Intersection Observer API 延迟加载图片的示例。我们将观察器附加到所有要延迟加载的图片上。一旦 API 检测到元素已进入视口,isIntersecting
我们会使用属性从 data-src 属性中提取 URL,并将其移动到 src 属性,以便浏览器触发图片加载。完成后,我们会从图片中移除 lazy 类,并移除该图片的观察器。
如果比较事件监听器和 Intersection Observer 这两种方法的图片加载时间,您会发现使用 Intersection Observer API 时,图片加载速度更快,而且网站滚动时也不会显得卡顿。在涉及事件监听器的方法中,我们不得不添加超时来提高性能,但这会对用户体验造成一些负面影响,因为图片加载会略微延迟。
然而,正如浏览器中所有新功能一样,Intersection Observer API并非在所有浏览器中都支持。因此,在不支持 Intersection Observer API 的浏览器中,我们需要回退到事件监听器方法。我们在上面的示例中已经考虑到了这一点。
延迟加载 CSS 背景图像
除了<img />
标签之外,背景图片是网页上最常见的图片加载方式。对于<img />
标签,浏览器的处理方式非常简单——如果图片 URL 可用,就加载图片。
对于 CSS 背景图像来说,情况就没那么简单了。要加载 CSS 背景图像,浏览器需要构建 DOM(文档对象模型)树和 CSSOM(CSS 对象模型)树,以确定 CSS 样式是否适用于当前文档中的 DOM 节点。如果指定背景图像的 CSS 规则不适用于文档中的某个元素,则浏览器不会加载该背景图像。如果 CSS 规则适用于当前文档中的某个元素,则浏览器会加载该图像。
这乍一看可能很复杂,但同样的行为构成了背景图片延迟加载技术的基础。简而言之,我们诱使浏览器background-image
在元素进入视口之前不将 CSS 属性应用于该元素。
这是一个延迟加载 CSS 背景图像的工作示例。
这里需要注意的是,延迟加载的 JavaScript 代码仍然相同。我们使用的是 Intersection Observer API 方法,并回退到事件监听器。诀窍在于 CSS。
ID 为 bg-image 的元素background-image
在 CSS 中指定了 。然而,当将 lazy 类添加到此元素时,我们会在 CSS 中覆盖该属性并将其设置为 none。由于与类background-image
组合的规则在 CSS 中比单独使用 具有更高的优先级,因此浏览器会首先将该属性应用于该元素。当我们向下滚动时,交叉点观察器(或事件监听器)检测到图像位于视口中,它会删除 类。这会更改适用的 CSS,并将实际的 background-image 属性应用于触发背景图像加载的元素。#bg-image
.lazy
#bg-image
background-image: none
lazy
通过延迟加载图像获得更好的用户体验
延迟加载带来了巨大的性能优势。对于一个页面上加载数百张产品图片的电商公司来说,延迟加载可以显著缩短页面初始加载时间,同时降低带宽消耗。然而,许多公司并不选择延迟加载,因为他们认为这不利于提供良好的用户体验——初始占位符不美观、加载时间缓慢等等。在本节中,我们将尝试通过图片延迟加载来解决一些用户体验方面的问题。
1. 使用正确的图像占位符
占位符是指在实际图像加载之前,容器中显示的内容。通常,我们会看到开发人员使用纯色占位符来表示图像,或者使用一张图片作为所有图像的占位符。
我们在示例代码中也使用了相同的方法。所有图片背景都使用了纯浅灰色。然而,我们可以做得更好,以提供更愉悦的用户体验。以下是一些使用更佳图片占位符的示例。
a. 主色占位符
我们不使用固定颜色作为图像占位符,而是从原始图像中找出主色作为占位符。这种技术在 Google 图片搜索结果和 Pinterest 中已经使用了相当长一段时间。
从Manu.ninja中选取的示例图像

这看起来可能很复杂。但其实,一个非常简单的方法是先将图片缩小到 1×1 像素,然后再放大到占位符的大小——虽然这个方法很粗略,但却是一个简单、快速获取单一主色的方法。使用 ImageKit,可以通过 ImageKit 中的链式变换获取主色占位符,如下所示。
使用 ImageKit 的主色占位符图像 URL 示例
占位符图像的大小仅为 661 字节,而原始图像的大小为 12700 字节,小了19 倍。并且,从占位符到实际图像的过渡体验更加流畅。
以下视频向用户演示了这种效果如何发挥作用。
b.低质量图像占位符(LQIP)
我们可以进一步扩展上述使用主色占位符的思路。我们不再使用单一颜色,而是使用原始图片的低质量模糊版本作为占位符。这样不仅看起来更好,还能让用户大致了解实际图片的内容,并让他们感觉到图片正在加载。这对于提升感知加载体验非常有效。Facebook 和 Medium.com 等公司已在其网站和应用的图片中使用这种技术。
使用 ImageKit 的 LQIP 图像 URL 示例
LQIP 的大小为 1300 字节,仍然比原始图像小近 10 倍,并且在视觉体验方面比任何其他占位符技术都有显著改善。
以下视频向用户演示了这种效果如何发挥作用。
从上述两种技术的视频样本中可以清楚地看出,使用主色占位符或使用低质量图像占位符可以提供从占位符到实际图像的更平滑的过渡,让用户了解将要替换该占位符的内容并改善加载感知。
2. 增加图片加载的缓冲时间
当我们讨论上面触发图像加载的不同方法时,我们检查了图像进入视口的时间点,即当图像占位符的顶部边缘与视口的底部边缘重合时触发图像加载。
问题
用户经常快速滚动页面,图片需要一些时间才能加载并显示在屏幕上。在这种情况下,再加上由于限流机制,加载图片事件可能会延迟触发,你经常会遇到这样的情况:占位符进入视口,用户需要等待几毫秒,然后图片才会显示出来。这种延迟会降低用户体验。
虽然使用交叉观察器加载图像或使用低质量的图像占位符可以提供更好的加载性能和用户体验,但还有另一个简单的技巧可用于确保图像在进入视口时始终完全加载 - 在图像的触发点引入边距。
解决方案
不要等到图片刚好进入视口时才加载,而是在图片距离进入视口还有(比如说)500px 时才加载。这样可以在加载触发和实际进入视口之间留出更多时间,让图片加载。
使用 Intersection Observer API,您可以将root
参数与rootMargin
参数(用作标准 CSS 边距规则)一起使用,以增大被认为用于查找“交点”的有效边界框。使用事件监听器方法,我们可以使用正数来添加阈值,而不是检查图像边缘与视口边缘之间的差异是否为 0。
这里的示例使用 500px 阈值来加载图像。
从下面的视频(仔细观察底部出现的网络请求)可以看出,滚动时,当第三张图片进入视图时,第五张图片已加载完毕。当第四张图片进入视图时,第六张图片已加载完毕。这样,我们就有足够的时间让图片完全加载,并且在大多数情况下,用户根本不会注意到占位符。
如果您之前没有注意到,在我们所有的示例中,第三张图片(image3.jpg)总是被预先加载,即使它位于视口之外。这也是遵循同样的原则——为了获得更好的用户体验,略微提前加载,而不是恰好在阈值处加载。
3. 通过延迟加载避免内容偏移
这是另一个琐碎的问题,如果解决了,可以帮助保持良好的用户体验。
问题
当没有图片时,浏览器不知道要显示在封闭容器中的内容的尺寸。如果我们不使用 CSS 指定尺寸,封闭容器将没有尺寸,即 0 x 0 像素。然后,当图片加载时,浏览器会调整封闭容器的大小以适应图片。这种布局的突然变化会导致其他元素移动,这被称为内容移动。正如 Smashing Magazine 的这篇关于内容移动的文章和视频所演示的那样,这对用户来说是一种相当不愉快的体验,因为内容会在图片加载时突然移动。
解决方案
可以通过指定容器的高度和/或宽度来避免这种情况,这样浏览器就可以用已知的高度和宽度来绘制图像容器。之后,当图像加载时,由于容器大小已经指定,并且图像完美地适应了容器,因此容器周围的其余内容不会移动。
4. 不要延迟加载所有图像
这是开发人员经常犯的另一个错误——延迟加载页面上的所有图片。这虽然可以减少页面的初始加载速度,但也会导致糟糕的用户体验,因为很多图片,即使是网页顶部的图片,也要等到 JavaScript 执行完毕才会显示。
我们可以遵循一些一般原则来确定哪些图像应该延迟加载。
a. 任何位于视口或网页开头的图像都不应延迟加载。这适用于任何标题图像、营销横幅、徽标等,因为用户应该在页面加载后立即看到它们。另外,请记住,移动设备和桌面设备的屏幕尺寸不同,因此初始屏幕上可见的图像数量也不同。因此,您需要考虑设备类型来决定哪些资源需要预先加载,哪些资源需要延迟加载。
b. 任何稍微偏离视口的图像都不应该延迟加载。这遵循了上面讨论的原则——提前加载。因此,假设任何距离视口底部 500px 或滚动一次的图像都可以提前加载。
c. 如果页面不长,可能只需要滚动一次或几次,或者视口外的图片少于 5 张,那么可以完全避免延迟加载。这不会给最终用户带来任何显著的性能提升。为了启用延迟加载而在页面上加载的额外 JS 代码会抵消延迟加载少量图片所带来的好处。
延迟加载的 Javascript 依赖
延迟加载的整个概念取决于用户浏览器中 JavaScript 执行功能的可用性。虽然大多数用户都会在浏览器中启用 JavaScript 执行功能(因为如今 JavaScript 执行功能对几乎所有网站都至关重要),但您可能需要为那些不允许在浏览器中执行 JavaScript 或使用完全不支持 JavaScript 的浏览器的用户做好规划。
您可以向他们显示一条消息,告知他们图片无法加载的原因,并告知他们需要切换到现代浏览器或启用 JavaScript。或者,您也可以使用 noscript 标签为这些用户打造可用的体验。对于这类用户,使用标签方法存在一些问题。Stack Overflow 上的这个问答主题很好地解决了这些问题,推荐任何想要解决这类用户问题的人阅读。
热门 JavaScript 库助您网站实现延迟加载
由于浏览器环境和实现细节可能因浏览器和设备而异,因此最好使用经过验证的延迟加载库。以下列出了一些热门库和特定平台的插件,让您能够以最少的精力实现延迟加载。
yall.js(又一个懒加载器) —— 使用 Intersection Observer 并回退到基于事件的懒加载。支持所有主流 HTML 元素类型,但不支持背景图片。也适用于 IE11+。
lazysizes – 非常流行且功能丰富。同时支持响应式图片的 srcset 和 size 属性。即使不使用 Intersection Observer 也能保持高性能。
jQuery Lazy – 一个简单的、基于 jquery 的延迟加载库。
WeltPixel 延迟加载增强功能– Magento 2 图像延迟加载扩展
Magento Lazy Image Loader – Magento 1.x 扩展,用于延迟加载图像
Shopify Lazy Image Plugin – Shopify 的一款图片延迟加载扩展程序。不过需要付费。
WordPress A3 Lazy Load – WordPress 图像延迟加载插件
如何测试延迟加载是否有效?
实现延迟加载后,您需要检查网站上图片的行为是否符合预期。最简单的方法是打开 Chrome 浏览器中的开发者工具。
前往“网络”选项卡 >“图片”。在这里,首次刷新页面时,只会加载需要优先加载的图片。然后,当您开始向下滚动页面时,其他图片加载请求将被触发并加载。您还可以在此视图的瀑布流列中看到图片加载的时间。这有助于您识别图片加载问题(如果有)或触发图片加载的问题。
另一种方法是在实施更改后在您的页面上运行 Google Chrome Lighthouse 审核报告,并在“屏幕外图像”部分下查找建议。
结论
本指南几乎涵盖了所有与图片延迟加载相关的内容。如果正确实施延迟加载,它将显著提升网页的加载性能,通过减少预先加载的不必要资源,减少页面大小并降低传输成本,同时保留页面上的必要内容。当您的用户通过更快的页面加载获得良好的体验时,他们也会感到欣喜。
那么,你还在等什么?立即开始使用延迟加载图像!
文章来源:https://dev.to/rnanwani/lazy-loading-images---the-complete-guide-2665