阿里云优惠活动,点击链接进行购买: 一年仅需96.9元即可以购买服务器~

腾讯云优惠活动, 点击链接进行购买一年仅需99元

腾讯云限时开团活动, 点击链接进行购买一年仅需95元

各大服务器厂商对比选购

# web 上的原生图片懒加载(译)

原文链接: https://addyosmani.com/blog/

在这篇文章中,我们将看一下新的加载 (opens new window)属性,它将原生的<img><iframe>延迟加载到网页上! 对于好奇的人来说,这里有一个实际的预览:

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

我们希望在 ~ Chrome 75 (opens new window) 能够正式使用以及正在深入研究我们即将发布的功能,让我们深入了解 loading 的工作原理。

# 引言

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

在以前,为了限制屏幕外图像对页面加载时间的影响,开发人员需要使用 JavaScript 库(如 LazySizes (opens new window))来推迟获取这些图像,直到用户在它们附近滚动。

without-lazyload@2x.png

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

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

# loading 属性

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

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

不指定属性将与设置 load = auto 具有相同的影响。

loading-attribute@2x.png

<img><iframe>的加载属性正在作为HTML 标准 (opens new window)的一部分进行处理。

# Example

loading 属性适用于<img>(包括 srcset 和<picture>内部)以及<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>

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

注意:我建议我们将其命名为 loading 属性,因为它的命名与解码属性更接近。 以前的提议,例如 lazyload 属性,并不是因为我们需要支持多个值(lazy, eager 和 auto)。

# 功能兼容性测试

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

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

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

# 跨浏览器图像 lazy-loading

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

标记需要使用类似<img data-src = unicorn.jpg />(而不是 src,srcset 或<source>)的东西,以避免在不支持新属性的浏览器中触发直接加载。 如果支持加载,可以使用 JavaScript 将这些属性更改为正确的属性,否则使用加载库。 你可以将其视为混合延迟加载。

# 下面是一个示例,展示了它可能的样子。

  • 视口内/上方图像是常规的<img>标签。data-src 会破坏预加载扫描程序,因此我们希望避免它出现在视口中的所有内容。
  • 我们在图像上使用 data-src 以避免在不受支持的浏览器中出现直接的 loading。 如果支持加载,我们将 data-src 转化为 src
  • 如果不支持加载,我们加载回退(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>
  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
    let script = document.createElement("script");
    script.async = true;
    script.src =
      "https://cdnjs.cloudflare.com/ajax/libs/lazysizes/4.1.8/lazysizes.min.js";
    document.body.appendChild(script);
  }
</script>

以上是上述的替代方法,它依赖于动态导入 (opens new window)来执行相同的降级库 fetching:

<!-- 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>

Andrea Verlicchi 有一篇很好的文章,也看到 hybrid lazy-loading (opens new window) 值得一读。

# Demo

A loading=lazy demo featuring exactly 100 kitten pics (opens new window) 是可用的。 看看这个!

# 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

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

lazy-load-devtools.png

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

# 确定服务器上的加载支持

在理想的情况下,您不需要依赖客户机上的 JavaScript 特性检测来决定是否需要加载降级库——您可以在提供包含 JavaScript 延迟加载库的 HTML 之前处理这个问题。客户机提示可以启用这样的检查。

正在考虑传递 loading 首选项的提示,但目前处于早期讨论阶段。

# 总结

<img loading>一个建议,让我们知道你的想法。 我对人们如何找到跨浏览器的故事以及是否有任何我们错过的边缘情况特别感兴趣。 我们希望今年夏天在 Chrome 76 上发布 loading 属性。

# 参考文献

  • https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/jxiJvQc-gVg/wurng4zZBQAJ
  • https://github.com/whatwg/html/pull/3752
  • https://github.com/scott-little/lazyload
  • https://mathiasbynens.be/demo/img-loading-lazy
Last Updated: 9/12/2022, 3:03:48 PM