[关闭]
@wy 2019-04-16T23:20:51.000000Z 字数 4998 阅读 889

为web提供原生的图片延迟加载

翻译


在这篇文章中,我们将看到新的 loading 属性,将实现原生的< img>< iframe>延迟加载到 web 网页上。对于好奇的人来说,先睹为快一段实际的预览代码:

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

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

介绍

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

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

'图片'
一个页面加载了211张图片。没有延迟加载的版本要获取10MB的图片数据。 延迟加载版本(使用LazySizes)预先加载250KB - 当用户滚动体验时,再获取其他图片。 见 WPT

如果浏览器可以避免为你加载这些屏幕之外的图片呢?这将有助于更快地加载视图端口(译者注:可视区域)中的内容,减少总体网络数据使用,并在低端设备上减少内存使用。好吧,我很高兴与大家分享,很快就可以在图片和 iframe 上使用新加载属性实现了。

loading 属性

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

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

https://addyosmani.com/assets/images/loading-attribute@2x.png

正在努力让 < img> and < iframe>loading 属性作为 HTML 标准( HTML standard)的一部分。

示例

loading 属性适用于 < img>(包括具有srcset和< picture>内部)以及 < iframe>

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

The exact heuristics for "when the user scrolls near" is left up to the browser.一般来说,我们希望浏览器能够在进入视口之前开始获取延迟的图片和iframe的一些内容。当用户滚动到它们时,这将提高图片或者iframe完成加载。

注意:我建议我们将其命名为 loading 属性,因为它的命名与 decoding 属性更接近。之前的提议,诸如 lazyload 属性没有使用,---------并不像我们需要的那样支持多个值(lazy, eagerauto)。

特征检测

我们牢记能够获取和应用 JavaScript 库去实现延迟加载的重要性(对于跨浏览器支持)。可以按如下方式检测对 loading 的支持:

  1. <script>
  2. if ('loading' in HTMLImageElement.prototype) {
  3. // Browser supports `loading`..
  4. } else {
  5. // Fetch and apply a polyfill/JavaScript library
  6. // for lazy-loading instead.
  7. }
  8. </script>

注意:您还可以把使用 loading 作为一种渐进增强。支持该属性的浏览器可以通过 loading=lazy 获得新的延迟加载行为,而那些不支持的浏览器仍然可以加载图片。

跨浏览器图片延迟加载

如果跨浏览器对延迟加载图片的支持很重要,那么在标签中使用 < img src=unicorn.jpg loading=lazy/> 时,仅使用功能检测和延迟加载的库是不够的。在标签中需要使用类似于 < img data-src=unicorn.jpg/>(而不是src、srcset或< source>)的内容,以避免在不支持新属性的浏览器中触发立马加载。如果支持 loading,可以使用 JavaScript 将这些属性更改为正确的属性,否则加载库来更改。

下面是一个这样的例子。

  1. <!-- Let's load this in-viewport image normally -->
  2. <img src="hero.jpg" alt=".."/>
  3. <!-- Let's lazy-load the rest of these images -->
  4. <img data-src="unicorn.jpg" loading="lazy" alt=".." class="lazyload"/>
  5. <img data-src="cats.jpg" loading="lazy" alt=".." class="lazyload"/>
  6. <img data-src="dogs.jpg" loading="lazy" alt=".." class="lazyload"/>
  7. <script>
  8. (async () => {
  9. if ('loading' in HTMLImageElement.prototype) {
  10. const images = document.querySelectorAll("img.lazyload");
  11. images.forEach(img => {
  12. img.src = img.dataset.src;
  13. });
  14. } else {
  15. // Dynamically import the LazySizes library
  16. const lazySizesLib = await import('/lazysizes.min.js');
  17. // Initiate LazySizes (reads data-src & class=lazyload)
  18. lazySizes.init(); // lazySizes works off a global.
  19. }
  20. })();
  21. </script>

Chrome 的实现细节

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

今天尝试

在地址栏输入 chrome://flags 并打开 "Enable lazy frame loading" 和 "Enable lazy image loading" 的标志,然后重启 Chrome

配置

Chrome 的延迟加载实现不仅基于当前滚动位置的远近,还基于连接速度。对于不同连接速度,延迟帧和图片加载距离视口的阈值是硬编码( hardcoded),但是可以通过命令行覆盖。下面是覆盖图片的延迟加载设置的示例:

  1. 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像素的变化(本文前面的视频使用):

  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

Chrome 中加载的实现细节是它在页面加载时获取前2KB的图像。 如果在服务器支持范围请求,则前2KB可能包含图像尺寸。 这使我们能够生成/显示具有相同尺寸的占位符。 前2KB也可能包括像图标这样的整个图片。
https://addyosmani.com/assets/images/lazy-load-devtools.png

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

决心在服务器上支持 loading

在理想的情况下,您不需要依赖客户端上的 JavaScript 特性检测来决定是否需要回退到引入库来完成加载—-—

结束

< img loading> 提一些建议让我们知道您的想法。我特别感兴趣的是人们如何找到跨浏览器的故事,以及我们是否遗漏了任何边缘情况。

参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注