【问题标题】:Lazyloading picture elements懒加载图片元素
【发布时间】:2015-04-22 18:46:53
【问题描述】:

我正在寻找有关如何最好地延迟加载图片元素的建议。我可能喜欢使用一个小的 jQuery 辅助函数来确定图片是否“在屏幕上”。但是 srcset 的懒惰获取,我现在不确定该怎么做。那么,有什么想法吗?

这是我正在使用的图片元素的示例。谢谢!

<picture alt="Random Celebrities" data-src="http://www.example.com/r/c_1,h_478,w_478/2015/03/19/random-celebrities-08-560x560.jpg">
    <!--[if IE 9]><video style="display: none;"><![endif]-->
    <source class='picture-source-1260' srcset='http://www.example.com/r/c_1,h_239,w_239/2015/03/19/random-celebrities-08-560x560.jpg, http://www.example.com/r/c_1,h_478,w_478/2015/03/19/random-celebrities-08-560x560.jpg 2x' media='(min-width: 1260px)'>
    <source class='picture-source-960' srcset='http://www.example.com/r/c_1,h_180,w_180/2015/03/19/random-celebrities-08-560x560.jpg, http://www.example.com/r/c_1,h_360,w_360/2015/03/19/random-celebrities-08-560x560.jpg 2x' media='(min-width: 960px)'>
    <source class='picture-source-760' srcset='http://www.example.com/r/c_1,h_150,w_150/2015/03/19/random-celebrities-08-560x560.jpg, http://www.example.com/r/c_1,h_300,w_300/2015/03/19/random-celebrities-08-560x560.jpg 2x' media='(min-width: 760px)'>
    <source class='picture-source-450' srcset='http://www.example.com/r/c_1,h_210,w_210/2015/03/19/random-celebrities-08-560x560.jpg, http://www.example.com/r/c_1,h_420,w_420/2015/03/19/random-celebrities-08-560x560.jpg 2x' media='(min-width: 450px)'>
    <source class='picture-source-320' srcset='http://www.example.com/r/c_1,h_160,w_160/2015/03/19/random-celebrities-08-560x560.jpg, http://www.example.com/r/c_1,h_320,w_320/2015/03/19/random-celebrities-08-560x560.jpg 2x'>
    <!--[if IE 9]></video><![endif]-->
    <noscript>
        <img class="picture-img-noscript" src="http://www.example.com/r/c_1,h_160,w_160/2015/03/19/random-celebrities-08-560x560.jpg" alt="Random Celebrities" />
    </noscript>
    <img class="picture-img" srcset="http://www.example.com/r/c_1,h_160,w_160/2015/03/19/random-celebrities-08-560x560.jpg" alt="Random Celebrities" />
</picture>

【问题讨论】:

  • 当我尝试为此问题添加标签“图片”或“图片元素”时,它会转换为“图片”。但为了澄清起见,我专门研究延迟加载使用图片标签和 srcset 定义的图像。
  • 浏览器延迟加载图片元素,如果你想复制浏览器使用的整个过程并使用JavaScript(大概是为了能够添加某种视觉过渡),那么你不要'不需要(并且可能不应该)使用图片元素作为占位符。
  • 所以“首屏下方”或以其他方式不在视口中的图片元素(轮播中的屏幕外等)在进入视口之前不会加载?
  • 我用错了术语。我的意思是延迟加载,因为根据视口/设备仅加载必要的图像(列表之外)。图片元素规范未指定浏览器应如何在视口之外加载图像,因此它们将在第一次渲染时加载。
  • 知道了。然后澄清一下,对于遇到这个问题的任何其他人,我希望推迟对实际图像的 http 请求,直到图片元素位于视口中。谢谢!

标签: jquery image lazy-loading


【解决方案1】:

我在这里创建了一个带有解决方案的笔:

https://stackoverflow.com/a/54092875/5858395

codepen

在 Chrome 和 Firefox、Safari 和 IE11 中测试(后者的后备)

<!-- Load images above the fold normally -->
<picture>
  <source srcset="img/city-m.jpg" media="(max-width: 960px)">
  <source srcset="img/city-l.jpg" media="(min-width: 961px)">
  <img class="fade-in" src="img/city-l.jpg" alt="city"/>
</picture>

<picture>
  <source srcset="img/forest-m.jpg" media="(max-width: 960px)">
  <source srcset="img/forest-l.jpg" media="(min-width: 961px)">
  <img class="fade-in" src="img/forest-l.jpg" alt="forest"/>
</picture>

<!-- Lazy load images below the fold -->
<picture class="lazy">
  <source data-srcset="img/river-m.jpg" media="(max-width: 960px)">
  <source data-srcset="img/river-l.jpg" media="(min-width: 961px)">
  <img data-srcset="img/river-l.jpg" alt="river"/>
</picture>

<picture class="lazy">
  <source data-srcset="img/desert-m.jpg" media="(max-width: 960px)">
  <source data-srcset="img/desert-l.jpg" media="(min-width: 961px)">
  <img data-srcset="img/desert-l.jpg" alt="desert"/>
</picture>

还有 JS:

document.addEventListener("DOMContentLoaded", function(event) {
   var lazyImages =[].slice.call(
    document.querySelectorAll(".lazy > source")
   )

   if ("IntersectionObserver" in window) {
      let lazyImageObserver = 
       new IntersectionObserver(function(entries, observer) {
          entries.forEach(function(entry) {
           if (entry.isIntersecting) {      
              let lazyImage = entry.target;
              lazyImage.srcset = lazyImage.dataset.srcset;
              lazyImage.nextElementSibling.srcset = lazyImage.dataset.srcset;
              lazyImage.nextElementSibling.classList.add('fade-in');
              lazyImage.parentElement.classList.remove("lazy");
             lazyImageObserver.unobserve(lazyImage);
            }
         });
        });

      lazyImages.forEach(function(lazyImage) {
       lazyImageObserver.observe(lazyImage);
      });
   } else {
     // Not supported, load all images immediately
    lazyImages.forEach(function(image){
        image.nextElementSibling.src = image.nextElementSibling.dataset.srcset;
      });
    }
  });

【讨论】:

  • 这只会延迟加载source元素,但不会延迟加载img元素。
  • @wp-overwatch.com,你能扩展一下吗?我只是在打开网络选项卡的情况下查看了 codpen,然后 img 在它们进入视口之前被添加到 som - 正如预期和描述的那样。
  • 如果向下滚动到延迟加载的底部图像,您会看到 DOM 中有 &lt;img data-srcset="https://i.ibb.co/D5QyVPk/desert-l.jpg" alt="image" srcset="https://i.ibb.co/D5QyVPk/desert-l.jpg" class="fade-in"&gt; 缺少有效的 src 属性。图片仍然是延迟加载的,因为源标签没问题,但是如果你删除所有的源标签,只剩下 img 标签,那么你会注意到没有任何图片加载。
  • @wp-overwatch.com,对不起,我不太明白。解决方案是什么?控制台中没有错误,并且所有 4 张图片都在我期望的时间加载。
  • 在彻底搜索解决方案之后,我可以说上面的代码仍然是我找到的唯一正确答案。根据我截至 2020 年 12 月的测试,所有流行的延迟加载脚本/插件都不能可靠地或根本无法与图片标签一起工作。@wp-overwatch.com 是正确的,代码忽略了 img 标签并且只处理了源标签.然而,发布的代码可以很容易地扩展,包括在图片标签内延迟加载 img 标签。在原生浏览器延迟加载无处不在之前,这个解决方案仍然适用于带有图片标签的完全延迟加载。
【解决方案2】:

使用lazysizes,它是用于普通和响应式图像(包括图片元素)的高性能延迟加载器。

【讨论】:

  • 感谢您的回复@alexander。那么我是否只需将所有源标签中的所有 srcset 实例更改为 data-srcset 并将类“lazyload”添加到 img 标签?还有一个小问题:lazysizes 可以用 RequireJS 作为模块加载吗?
  • 是的,没错,你可以使用 requireJS 来加载惰性大小。 lazysizes 本身正在使用未命名的 umd 模块模式。
  • 感谢您的快速回复,@alexander。欣赏lazysizes 使用UMD。将此标记为最佳答案。 (但我可能会问,如果我还有其他问题!)
  • 还有一个问题@alexander。异步添加到 DOM 的元素的惰性大小如何?
  • 看起来你是这个库的作者。请按照stackoverflow.com/help/promotion 在您的回答中披露您的隶属关系
【解决方案3】:

你其实不需要插件,只要在你的图片标签上放一个类,去掉里面的“img”标签,把src放在srcset里面:

 <picture class="lazy">
   <source srcset='/images/image.jpg'/>
 </picture>

然后在你的 dom 加载后在 javascript 中:

获取所有“.lazy”节点:

const lazyImages = document.querySelectorAll('.lazy');

这样调用函数:

 function lazyLoadImages() {
   lazyImages.forEach((val,i) => {

     let src = val.querySelector('source').getAttribute('srcset');
     let image = new Image();
     image.src = src;
     val.append(image);


   })
 }

【讨论】:

  • 请不要删除 标签 - 标签需要一个 才能成为有效的 html 并在旧浏览器上正确回退。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-22
  • 2018-09-04
  • 1970-01-01
  • 2013-12-25
  • 1970-01-01
相关资源
最近更新 更多