Ленивая загрузка тега изображения HTML5

Я искал (безуспешно) надежный способ ленивой загрузки изображений при использовании спецификации HTML5 для <picture>, Большинство решений / плагинов в настоящее время полагаются на использование data- атрибутов. Я могу ошибаться, но не похоже, что этот метод будет работать в сочетании с <picture>,

Я действительно просто хочу, чтобы меня указали в правильном направлении. Если у кого-нибудь есть решение, которое они используют в настоящее время, я бы с удовольствием посмотрел. Спасибо!

ОБНОВИТЬ:
Вот стандартная разметка согласно спецификации HTML5:

<picture width="500" height="500">
    <source media="(min-width: 45em)" src="large.jpg">
    <source media="(min-width: 18em)" src="med.jpg">
    <source src="small.jpg">
    <img src="small.jpg" alt="">
</picture>

4 ответа

Решение

Для тех, кто все еще заинтересован... После повторного рассмотрения этой проблемы я наткнулся на довольно новый скрипт под названием Lazysizes. Это на самом деле довольно универсально, но что более важно, это позволяет мне выполнять ленивую загрузку изображений, используя разметку HTML5, как описано в OP.

Большое спасибо создателю этого скрипта, @aFarkas.

На дворе февраль 2020 года, и я рад сообщить, что Google Chrome, Microsoft Edge (Edge на основе Chromium) и Mozilla Firefox поддерживают новыйloading="lazy"атрибут. Единственный недостаток современного браузера - это Apple Safari (как iOS Safari, так и macOS Safari), но они недавно завершили добавление его в кодовую базу Safari, поэтому я ожидаю, что он будет выпущен где-то в этом году.

В loading="lazy" атрибут только для <img /> элемент (а не <picture>) но помните, что <picture>элемент не представляет фактическое замененное содержимое,<img /> элемент выполняет (т.е. изображение, которое видят пользователи, всегда отображается <img /> элемент, <picture> элемент просто означает, что браузер может изменить <img src="" />атрибут. Из спецификации HTML5 по состоянию на февраль 2020 года (выделено мной):

В picture элемент несколько отличается от похожего на вид video а также audioэлементы. Хотя все они содержатsource элементы, source элемент src атрибут не имеет значения, если элемент вложен в pictureэлемент, а алгоритм выбора ресурса другой. Так жеpictureсам элемент ничего не отображает; он просто предоставляет контекст для содержащихсяimgэлемент, который позволяет ему выбирать из нескольких URL-адресов.

Так что это должно работать:

<picture width="500" height="500">
    <source media="(min-width: 45em)" src="large.jpg" />
    <source media="(min-width: 18em)" src="med.jpg" />
    <source src="small.jpg" />
    <img src="small.jpg" alt="" loading="lazy" />
</picture>

Рабочий пример отложенной загрузки изображений с использованием элемента изображения и наблюдателя пересечения, протестированных в Chrome и Firefox. Safari не поддерживает средство наблюдения пересечения, поэтому изображения загружаются немедленно, а IE11 не поддерживает элемент, поэтому мы возвращаемся к значению по умолчанию img

Медиа-запросы в медиа-атрибуте являются произвольными и могут быть установлены в соответствии с требованиями.

Порог ширины установлен в 960 пикселей - попробуйте перезагрузить выше и ниже этой ширины, чтобы увидеть изменение среднего (-m) или большого (-l) изображения, загружаемого при прокрутке изображения в окне просмотра.

Codepen

<!-- 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;
      });
    }
  });

Еще одна мысль: если вы меняете ширину экрана вперед и назад, файлы изображений повторно загружаются снова. Если бы я мог привязать вышеописанный метод к проверке кэша, то это было бы прекрасно...

В web.dev Google сообщает, что теги изображений можно загружать лениво.
https://web.dev/browser-level-image-lazy-loading/

Изображения, определенные с помощью этого элемента, также можно загружать лениво:

      <picture>
  <source media="(min-width: 800px)" srcset="large.jpg 1x, larger.jpg 2x">
  <img src="photo.jpg" loading="lazy">
</picture>

Хотя браузер решает, какое изображение загружать из любого из элементов, атрибут загрузки нужно только включить в резервный элемент.

Другие вопросы по тегам