专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

如何使用浏览器原生 API 实现图片懒加载功能

ins518 2024-10-07 13:28:00 技术文章 11 ℃ 0 评论

在这篇文章中,我们将看看 <img> 和 <iframe> 新增的可以实现懒加载的 loading 属性。对于好奇的人来说,这里有一个实际的预览:

<img src="celebration.jpg" loading="lazy" alt="..." />
<iframe src="video-player.html" loading="lazy"></iframe>

我们希望能够为loading~ Chrome 75提供支持,并正在深入研究我们即将发布的功能。在那之前,让我们深入了解它的 loading 工作原理。

介绍

网页通常包含大量图像,这些图像会导致数据使用,页面膨胀以及页面加载的速度。许多这些图像都在屏幕外,需要用户滚动才能查看它们。

从历史上看,为了限制屏幕外图像对页面加载时间的影响,开发人员需要使用JavaScript库(如LazySizes)来推迟获取这些图像,直到用户滚动它们为止。

如果浏览器可以避免为您加载这些屏幕外图像怎么办?这将有助于更快地加载视图端口中的内容,减少整体网络数据使用和低端设备,减少内存使用。嗯,我很高兴地分享,很快就可以使用 loading 图片和 iframe 的新属性。

loading 属性

该 loading 属性允许浏览器推迟加载屏幕外图像和iframe,直到用户在它们附近滚动。loading支持三个值:

  • lazy:是一个很好的懒人加载候选人。
  • eager:不适合延迟加载。马上加载。
  • auto:浏览器将确定是否延迟加载。

根本不指定属性将产生与设置相同的影响loading=auto。

作为HTML标准的一部分的loading属性<img>和<iframe>正在处理 的属性。

例子

该loading属性适用于<img>(包括with srcset和inside <picture>)以及on <iframe>:

<!-- Lazy-load an offscreen image when the user scrolls near it -->
<img src="unicorn.jpg" loading="lazy" alt=".."/>
<!-- Load an image right away instead of lazy-loading -->
<img src="unicorn.jpg" loading="eager" alt=".."/>
<!-- Browser decides whether or not to lazy-load the image -->
<img src="unicorn.jpg" loading="auto" alt=".."/>
<!-- Lazy-load images in <picture>. <img> is the one driving image 
loading so <picture> and srcset fall off of that -->
<picture>
 <source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x">
 <source srcset="small.jpg 1x, small-hd.jpg 2x">
 <img src="fallback.jpg" loading="lazy">
</picture>
<!-- Lazy-load an image that has srcset specified -->
<img src="small.jpg"
 srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
 sizes="(min-width: 36em) 33.3vw, 100vw"
 alt="A rad wolf" loading="lazy">
<!-- Lazy-load an offscreen iframe when the user scrolls near it -->
<iframe src="video-player.html" loading="lazy"></iframe>

“当用户滚动到附近时”的确切启发式方法留给浏览器。一般来说,我们希望浏览器在进入视口之前会开始提取延迟图像和iframe内容。这将增加图像或iframe在用户滚动到它们时完成加载的更改。

注意:我建议我们将该loading属性命名为该属性,因为它的命名与decoding属性更接近。之前的提议,例如lazyload属性没有成功,因为我们需要支持多个值(lazy,eager和auto)。

特征检测

我们一直在考虑能够为延迟加载提取和应用JavaScript库的重要性(对于跨浏览器支持)。支持loading功能可以如下检测:

<script>
if ('loading' in HTMLImageElement.prototype) { 
 // Browser supports `loading`..
} else {
 // Fetch and apply a polyfill/JavaScript library
 // for lazy-loading instead.
}
</script>

注意:您还可以使用loading渐进增强功能。支持该属性的浏览器可以获得新的延迟加载行为,loading=lazy而不支持该属性的浏览器仍然会加载图像。

跨浏览器图像延迟加载

如果对延迟加载图像的跨浏览器支持很重要,那么如果您<img src=unicorn.jpg loading=lazy />在标记中使用,则仅对功能检测和延迟加载库是不够的。

该标记需要使用类似<img data-src=unicorn.jpg />(而不是src,srcset或<source>),以避免触发浏览器中的贪婪加载不支持新的属性。如果loading支持,可以使用JavaScript将这些属性更改为正确的属性,否则加载库。

下面是一个这样的例子。

  • 视口内/上方图像是常规<img>标签。A data-src会破坏预加载扫描程序,因此我们希望避免它出现在视口中的所有内容。
  • 我们data-src在图像上使用以避免在不受支持的浏览器中产生急切的负载。如果loading支持,我们换data-src了src。
  • 如果loading不受支持,我们加载一个后备(LazySizes)并启动它。在这里,我们使用class=lazyload一种方式向LazySizes图像指示我们想要延迟加载。
<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt=".."/>
<!-- Let's lazy-load the rest of these images -->
<img data-src="unicorn.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="cats.jpg" loading="lazy" alt=".." class="lazyload"/>
<img data-src="dogs.jpg" loading="lazy" alt=".." class="lazyload"/>
<script>
(async () => {
 if ('loading' in HTMLImageElement.prototype) {
 const images = document.querySelectorAll("img.lazyload");
 images.forEach(img => {
 img.src = img.dataset.src;
 });
 } else {
 // Dynamically import the LazySizes library
 const lazySizesLib = await import('/lazysizes.min.js');
 // Initiate LazySizes (reads data-src & class=lazyload)
 lazySizes.init(); // lazySizes works off a global.
 }
})();
</script>

Demo

一个 loading=lazy 配有整整100小猫图片演示可用。看看这个!

https://mathiasbynens.be/demo/img-loading-lazy

Chrome实施细节

我们强烈建议loading您在生产中使用之前等待属性处于稳定版本。早期测试人员可能会发现以下注释很有帮助。

今天试试吧

转到chrome://flags并启用“启用延迟帧加载”和“启用延迟图像加载”标志,然后重新启动Chrome。

组态

Chrome的延迟加载实现不仅基于当前滚动位置的接近程度,还基于连接速度。对于不同连接速度,延迟帧和图像加载距离视口阈值是硬编码的,但可以从命令行覆盖。这是一个覆盖图像的延迟加载设置的示例:

canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=5000,lazyImageLoadingDistanceThresholdPxOffline=8000,lazyImageLoadingDistanceThresholdPxSlow2G=8000,lazyImageLoadingDistanceThresholdPx2G=6000,lazyImageLoadingDistanceThresholdPx3G=4000,lazyImageLoadingDistanceThresholdPx4G=3000 'https://mathiasbynens.be/demo/img-loading-lazy'

以上命令对应于(当前)默认配置。将所有值更改400为仅在滚动位置在图像的400像素内时开始延迟加载。下面我们还可以看到1像素的变化(本文前面的视频使用):

canary --user-data-dir="$(mktemp -d)" --enable-features=LazyImageLoading --blink-settings=lazyImageLoadingDistanceThresholdPxUnknown=1,lazyImageLoadingDistanceThresholdPxOffline=1,lazyImageLoadingDistanceThresholdPxSlow2G=1,lazyImageLoadingDistanceThresholdPx2G=1,lazyImageLoadingDistanceThresholdPx3G=1,lazyImageLoadingDistanceThresholdPx4G=1 'https://mathiasbynens.be/demo/img-loading-lazy'

随着实施在未来几周内稳定,我们的默认配置很可能会发生变化。

DevTools

loadingChrome中的一个实现细节是它在页面加载时获取前2KB的图像。如果服务器支持范围请求,则前2KB可能包含图像尺寸。这使我们能够生成/显示具有相同尺寸的占位符。前2KB也可能包括像图标这样的资产的整个图像。

当用户即将看到它时,Chrome会抓取其余的图像字节。Chrome DevTools的一个警告是,这可能导致(1)在DevTools网络面板中“出现”双重提取和(2)资源计时对每个图像有2个请求。

确定loading服务器上的支持

在一个完美的世界中,您不需要依赖客户端上的JavaScript功能检测来决定是否需要加载回退库 - 您需要在提供包含JavaScript延迟加载库的HTML之前处理此问题。客户端提示可以启用此类检查。

loading正在考虑传达偏好的提示,但目前正处于早期讨论阶段。

包起来

给<img loading>旋,让我们知道您的想法。我对人们如何找到跨浏览器的故事以及是否有任何我们错过的边缘情况特别感兴趣。

参考

  • 意图在Blink中发布此功能(https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/jxiJvQc-gVg/wurng4zZBQAJ)
  • 规格PR(https://github.com/whatwg/html/pull/3752)
  • 解释器(https://github.com/scott-little/lazyload)
  • Demo(https://mathiasbynens.be/demo/img-loading-lazy)

感谢Simon Pieters,Yoav Weiss和Mathias Bynens的反馈。非常感谢Ben Greenstein,Scott Little,Raj T和Houssein Djirdeh在LazyLoad上的工作。

原文:https://addyosmani.com/blog/lazy-loading/

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表