5 приёмов ленивой загрузки изображений

Поскольку изображения сохраняют лидерство среди самых популярных типов контента в интернете, большое количество картинок на странице очень быстро становится проблемой и, в первую очередь, это влияет на время загрузки страниц. Есть несколько способов как-то повлиять на положительное решение этой проблемы. В этой статье будут рассмотрены пять приёмов отложенной загрузки изображений, которые можете добавить в свой инструментарий веб-оптимизации, чтобы улучшить взаимодействие с пользователем на вашем веб-сайте.

Что такое Lazy Loading (ленивая загрузка)?

Ленивая загрузка изображений означает асинхронную загрузку картинок веб-страницы, то есть после полной загрузки контента или даже условно, только когда они появляются в видимой части окна браузера. Это означает, что если пользователи не будут прокручивать страницу, изображения, размещенные за пределами видимой части окна, даже не будут загружены.

Некоторые веб-сайты используют этот подход, но чаще всего это можно встретить на сайтах с большим количеством изображений. Попробуйте поискать фотографии в высоком разрешении в своем любимом онлайн-поисковике, и вы скоро поймете, как веб-сайт загружает только ограниченное количество изображений. Прокручивая страницу вниз, вы увидите, что изображения-заглушки быстро заполнятся реальными изображениями для предварительного просмотра.

Почему вы должны позаботиться о ленивой загрузке изображений?

Есть по крайней мере несколько веских причин, по которым вам стоит задуматься о ленивой загрузке изображений для вашего сайта:

  • Если ваш веб-сайт использует JavaScript для отображения содержимого или предоставления пользователям какой-либо функциональности, время загрузки DOM очень скоро становится узким местом в производительности страниц. Скрипты, прежде чем начать работать, обычно ждут полной загрузки DOM. На сайте со значительным количеством изображений, отложенная загрузка, или загрузка изображений асинхронно, может иметь решающее значение для пользователей, которые начинают размышлять: оставаться и подождать или уже покинуть ваш сайт.
  • Поскольку большинство решений загружают изображения только в том случае, когда пользователь прокрутил до места, где они станут видны внутри области просмотра, то эти изображения никогда не будут загружены, если пользователи никогда не достигнут этой точки. Это означает значительную экономию трафика, за что большинство пользователей, особенно с доступом к Интернету на мобильных устройствах и медленных соединениях, будут вам благодарны.

Если ленивая загрузка изображений помогает повысить производительность сайта, то как лучше это сделать?

Вряд ли существует идеальный вариант.

Если вы живете и дышите JavaScript, реализация собственного lazy load решения не должна быть проблемой. Ничто не даёт вам больше контроля, чем кодирование чего-либо самостоятельно. Кроме того, вы можете просматривать веб-страницы для поиска подходящих подходов и поэкспериментировать с ними.

№1 Нативный lazy load

Нативная ленивая загрузка для img и iframe очень крутая. Ничто не может быть более простым, чем такая разметка:

<img src="myimage.jpg" loading="lazy" alt="..." />
<iframe src="content.html" loading="lazy"></iframe>

Как видите, нет JavaScript, нет динамической подмены значения атрибута src, просто «старый, тёплый, ламповый» HTML.

Атрибут loading даёт возможность задерживать скрытые за пределами окна изображения и фреймы, пока пользователь не прокрутит страницу до них. loading может принимать любое из этих трёх значений:

  • lazy: отличный вариант для ленивой загрузки
  • eager: указывает браузеру не ждать и загружать контент сразу
  • auto: оставляет опцию включения отложенной загрузки на усмотрение браузера

У этого метода нет конкурентов: у него нет ничего лишнего, он чистый и простой. Однако, хотя на момент написания статьи большинство основных браузеров уже хорошо поддерживают атрибут loading, большинство — это ещё не все.

№2 Ленивая загрузка с использованием API Intersection Observer

Intersection Observer API — это современный интерфейс, который вы можете использовать для отложенной загрузки изображений и другого контента. Вот как MDN представляет этот API:

Intersection Observer API позволяет веб-приложениям асинхронно следить за изменением пересечения элемента с его родителем или областью видимости документа viewport.

Тут всё понятно: асинхронно отслеживается пересечение одного элемента с другим. Допустим, вы хотите лениво загрузить галерею изображений. Разметка для каждого изображения будет выглядеть так:

<img data-src="image.jpg" alt="test image">

Обратите внимание, что путь к изображению содержится внутри атрибута data-src, а не src. Причина в том, что при использовании src изображение будет загружаться немедленно.

В CSS вы указываете каждому изображению значение минимальной высоты, скажем, 100px. Это резервирует место каждому изображению (элемент img без атрибута src):

img {
  min-height: 100px;
  /* остальные стили */
}

В JavaScript вы добавляете объект с конфигурацией и регистрируете его в экземпляре intersectionObserver:

// конфиг: rootMargin и порог срабатывания
// два свойства, представленные интерфейсом
const config = {
  rootMargin: '0px 0px 50px 0px',
  threshold: 0
};
// регистрируем config с экземпляром
// intersectionObserver
let observer = new intersectionObserver(function(entries, self) {
  // перебираем записи
  entries.forEach(entry => {
    // обрабатывать только изображения, которые пересекают
    // isIntersecting - это свойство предоставляется интерфейсом
    if(entry.isIntersecting) {
      // функция, которая копирует путь к IMG
      // из data-src в src
      preloadImage(entry.target);
      // изображение теперь на месте, прекращаем наблюдение
      self.unobserve(entry.target);
    }
  });
}, config);

Затем, надо перебрать все изображения и добавить их в этот экземпляр iterationObserver:

const imgs = document.querySelectorAll('[data-src]');
imgs.forEach(img => {
  observer.observe(img);
});

Преимущества этого решения: его легко внедрить, оно эффективно и перекладывает выполнение тяжелых вычислений на API intersectionObserver.

С другой стороны, хотя API-интерфейс Intersection Observer поддерживается большинством последних версий браузеров, но не всеми. Однако, для маргинальных браузеров доступен полифилл.

Вы можете узнать больше об API Intersection Observer и подробностях реализации в этой статье.

№3 Lozad.js

Быстрая и простая альтернатива реализации для ленивой загрузки изображений — позволить выполнить большую часть работы готовой JS-библиотеке.

Lozad.js — это высокопроизводительный, легкий и настраиваемый ленивый загрузчик на чистом JavaScript и без каких-либо зависимостей. Его можно использовать для отложенной загрузки изображений, видео, iframe и т.д. И он использует API Intersection Observer.

Lozad.js можно подключить с помощью npm/yarn:

npm install --save lozad
// или
yarn add lozad

и импортировать его:

import lozad from 'lozad';

Кроме того, вы можете просто загрузить библиотеку с помощью CDN и добавить ее в конец HTML-страницы в теге <script>:

<script src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>

Далее, для базовой реализации, добавьте css-класс lozad html-элементам в разметке:

<img class="lozad" data-src="img.jpg">

Наконец, в JS создайте экземпляр Lozad:

const observer = lozad();
observer.observe();

Если нет желания углубляться в работу API-интерфейса Intersection Observer или просто ищете быструю реализацию, применимую к различным типам контента, Lozad — отличный выбор.

Только следует помнить о поддержке маргинальных браузеров, для API Intersection Observer всё еще требуется polyfill.

№4 Отложенная загрузка с эффектом размытия

Если читаете Medium.com, то наверняка заметили, как сайт загружает основное изображение внутри поста. Первое, что увидите, это размытая копия изображения с низким разрешением, тогда как его версия с высоким разрешением лениво загружается:

Размытое изображение-заглушка на сайте Medium.com

Лениво загруженное изображение высокого разрешения на веб-сайте Medium.com

Лениво загружать изображения с этим интересным эффектом размытия можно несколькими способами. Вот один из них:

  • Небольшой объём: всего 463 байта CSS и 1 007 байтов минимизированного JS
  • Поддержка ретины
  • Нет зависимостей: не использует jQuery или другие библиотеки и фреймворки

№5 Yall.js

Yall.js — это многофункциональный скрипт для ленивой загрузки изображений, видео и iframe. Он использует Intersection Observer API и, при необходимости, использует интеллектуальные методы обработки событий.

Для использования Yall его нужно инициализировать так:

<script src="yall.min.js"></script>
<script>
  document.addEventListener("DOMContentLoaded", yall);
</script>

Затем, для ленивой загрузки элемента img, нужно написать в разметке:

<img class="lazy"
  src="placeholder.jpg"
  data-src="image-to-lazy-load.jpg"
  alt="Описание для изображения">

На что следует обратить внимание:

  • Элементу надо добавить css-класс lazy
  • В значение src надо указать путь к картинке-заглушке
  • Путь к картинке, которую надо будет загрузить, надо написать в атрибуте data-src

Особенности Yall.js

  • хорошая производительность за счет использования Intersection Observer API
  • поддержка маргинальных браузеров (в т.ч. IE11)
  • не использует внешние зависимости