• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

使用 HTML 和 JavaScript 延迟加载图像

之前写过一篇教程,讨论如何使用 htmlcssjavascript在网页上预加载图像。我们不厌其烦地预加载图片的原因是为了向用户提供更好的浏览体验,这样他们就不必等待图片加载。

改善用户体验的相同理念也适用于延迟加载图像。当我们浏览网站时,图像是页面重量的最大贡献者之一。以最佳方式加载它们可以提高性能并节省带宽。

在本教程中,我们将了解延迟加载图像的不同方法。

延迟加载图像的需要

我们将通过学习为什么你应该为延迟加载图像而烦恼来开始本教程。假设您正在为一位摄影师构建一个作品集网站,他们在一个页面上展示了他们所有的最佳图像。

不是每个人都会滚动到页面底部来查看所有图像。但是,图像仍会由用户的浏览器下载。这在下面的 CodePen 演示中很明显:

See the Pen  Loading Multiple Images by Monty (@Shokeen)  on CodePen.

即使您不滚动上面演示中的第一张图片,您也会看到浏览器已加载所有图片。下面是我浏览器开发人员工具中“网络”选项卡的屏幕截图,显示发出了 38 个请求,传输了大约 2.5MB 的数据。浏览器总共下载了 19 张图像,重定向使请求数量翻了一番。

使用 HTML 和 JavaScript 延迟加载图像  第1张

我们现在将尝试改进或优化图像加载以节省资源。

使用 HTML 延迟加载图像

延迟加载图像的最简单方法涉及使用属性loading。所有现代浏览器都支持loading图像上的属性,该属性可用于指示浏览器在图像离开屏幕时阻止加载图像,并且仅在用户滚动到足够近以使其可见时才开始加载图像。

该loading属性可以接受两个可能的值。第一个值是eager,它告诉浏览器立即加载图像,即使它当前不在视口内。这是浏览器的默认行为。

第二个值是lazy,它告诉浏览器延迟加载图像,直到它达到距视口的特定距离。此距离由浏览器定义。将属性的值设置loading为lazy可以潜在地为客户端节省带宽。

重要的是要记住,浏览器只会延迟加载当前在视口中不可见的图像。通常,网页上的图像与其他文本一起放置,将它们推到视口之外。在这种情况下,您不需要做任何特殊的事情来确保图像延迟加载。

但是,请考虑本教程中的示例,其中网页仅包含图像。在这种情况下,如果您希望延迟加载图像,那么提及图像的大小就变得很重要。否则,所有图像最初都将具有零宽度和零高度。这将使浏览器认为所有图像在视口中都是可见的,并且会立即加载所有图像。

<img  loading= "lazy"  src= "https://picsum.photos/id/628/1080/1080"  width= "600"  height= "600" >

在这种情况下显式指定图像宽度和高度会将一些图像推出视口。您可以使用width和heightHTML 属性或在 CSS 中自由指定图像尺寸。

这是将延迟加载图像的标记:

正如我之前所说,您还可以在 CSS 中指定图像尺寸并从标记中删除width和属性:height

<img  loading= "lazy"  src= "https://picsum.photos/id/628/1080/1080" >

相应的 CSS 将是:

img {
  width: 600px;
  height: 600px;
}

以下 CodePen 演示展示了延迟加载的实际效果:

See the Pen  Lazy Loading Multiple Images (HTML) by Monty (@Shokeen)  on CodePen.

我浏览器的开发者工具中的网络选项卡显示这次只下载了四张图片,传输了大约 450 kB 的数据。页面上一共有19张图片,也就是说还有15张会懒得下载。就带宽而言,这意味着节省了大约 80%。

使用 HTML 和 JavaScript 延迟加载图像  第2张

这里要记住的一件重要事情是,即使不涉及脚本,图像的延迟加载也只有在启用 JavaScript 时才有效。这样做是为了防止通过策略性放置的图像跟踪用户的滚动位置。

浏览器如何确定何时应该下载应该延迟加载的图像?触发延迟加载图像下载的确切条件因浏览器而异。然而,两个主要因素似乎是与视口的距离和网络速度。

如果你想精确控制延迟加载图像的下载时间,那么你将不得不使用 javaScript。

使用 JavaScript 延迟加载图像

现在我们将学习如何使用 JavaScript 延迟加载图像。这将使我们能够更好地控制整个过程。如果您认为默认的延迟加载不够积极,您可以使用 Intersection Observer api 创建自己的延迟加载脚本。

在我们编写任何 JavaScript 之前,我们需要对我们的标记进行一些更改:

<img  class= "lazy-load"  data-src= "https://picsum.photos/id/628/1080/1080" >

我们的img标签现在将包含一个名为lazy-load帮助我们识别哪些图像需要延迟加载的类。标签将使用属性来跟踪图像路径,而不是src属性。这可以防止图像立即开始下载。imgdata-src

Intersection Observer API 允许我们检测我们的目标元素是否与其任何祖先元素或文档的视口相交。我们将使用IntersectionObserver()构造函数来创建我们的IntersectionObserver对象。构造函数接受一个回调函数作为它的第一个参数,一个可选的对象作为第二个参数来定制观察者的行为。

我们传递给构造函数的回调函数接收两个参数。第一个是相交元素的数组,第二个是观察者本身。自定义选项允许您指定要检查交集的根元素、向根元素添加额外偏移值的根边距,以及确定浏览器应何时开始报告交集的阈值。

这是我们的路口观察者对象的代码:

function preload_image(img) {
  img.src = img.dataset.src;
  console.log(`Loading ${img.src}`);
}
const config_opts = {
  rootMargin: '200px 200px 200px 200px'
};
let observer = new IntersectionObserver(function(entries, self) {
  for(entry of entries) { 
    if(entry.isIntersecting) {
      let elem = entry.target;
      preload_image(elem);   
      self.unobserve(elem);
    }
  }
}, config_opts);

我在我们的根元素或本例中的视口的所有边上提供了 200 像素的边距。只要任何图像在视口 200 像素以内,我们的交叉点观察器就会激活。默认情况下,阈值设置为 0。零值意味着preload_image()只要图像的一小部分在我们指定的范围内,就会调用该函数。该unobserve()方法告诉浏览器停止观察此特定图像以进行进一步的交叉。

该函数获取图像的属性preload_image()值并将其应用于属性。这会触发我们图像的下载。data-srcsrc

我们现在需要做的就是查询文档中的所有图像,然后告诉观察者观察它们是否相交。这是为我们实现此目的的代码。

let images = document.queryselectorAll('img.lazy-load');
for(image of images) {
  observer.observe(image);
}

您是否注意到我们正在使用img.lazy-load选择器来查询我们的图像?这个类帮助我们轻松识别我们想要延迟加载的所有图像。没有此类的图像将正常加载。

这是一个 CodePen 演示,用于查看我们的图像是否确实延迟加载。

See the Pen  Lazy Loading Multiple Images (JavaScript) by Monty (@Shokeen)  on CodePen.

这一次,我浏览器的开发者工具中的网络选项卡显示预先只下载了两张图片,总数据传输量约为 192 kB。与我们最初的演示相比,我们的带宽节省现在高达 92%。

使用 HTML 和 JavaScript 延迟加载图像  第3张

我承认我已经让路口观察器变得非常激进,只加载非常靠近视口的图像。然而,这就是您自己实现功能的美妙之处。

最后的想法

延迟加载图像对每个人都是双赢的。它将减少服务器的负载,同时节省用户的带宽。请记住,数据,尤其是移动数据,在世界某些地方非常昂贵。

既然浏览器自带延迟加载图像的本机支持,只需对标记进行微小更改即可充分利用该功能。浏览器也足够聪明,可以根据网络速度和图像位置确定理想的延迟加载图像时间。您还可以使用 Intersection Observer API 相对轻松地自行实现该功能。

这里要牢记的一件重要事情是,如果在用户端禁用了 JavaScript,那么这些技术都将不起作用。

文章目录
  • 延迟加载图像的需要
  • 使用 HTML 延迟加载图像
  • 使用 JavaScript 延迟加载图像
  • 最后的想法
  • 发表评论