Отложенная загрузка изображений
Изображения могут появляться на веб-странице вследствие встраивания в HTML-код с помощью тега <img>
или как фоновые изображения CSS. В этом статье вы узнаете, как отложить загрузку обоих типов изображений.
Встроенные изображения #
Наиболее распространенные кандидаты на отложенную загрузку — это изображения, используемые в элементах <img>
. Для встроенных изображений имеется три варианта отложенной загрузки, которые можно сочетать между собой для лучшей кроссбраузерной совместимости:
- Использование отложенной загрузки на уровне браузера.
- Использование Intersection Observer.
- Использование обработчиков событий прокрутки и изменения размера.
Использование отложенной загрузки на уровне браузера #
Chrome и Firefox поддерживают отложенную загрузку с атрибутом loading
. Этот атрибут можно добавить к <img>
, а также к элементам <iframe>
. Значение lazy
указывает браузеру, что нужно немедленно загрузить изображение, если оно находится в области просмотра, и получить другие изображения, когда пользователь при прокрутке страницы приблизится к их расположению.
Чтобы узнать о поддержке атрибута браузерами на текущий момент, взгляните на строку loading
в таблице MDN «Поддержка браузерами». Если браузер не поддерживает отложенную загрузку, то атрибут будет проигнорирован, и изображения будут загружаться сразу, как обычно.
Для большинства веб-сайтов добавление этого атрибута к встроенным изображениям повысит производительность и избавит пользователей от загрузки изображений, до которых они никогда не докрутят страницу. Если у вас есть большое количество изображений и вы хотите быть уверены, что пользователи браузеров без поддержки отложенной загрузки смогут воспользоваться ее преимуществами, объедините этот метод с одним из описанных ниже.
Чтобы узнать больше, ознакомьтесь со статьей «Отложенная загрузка изображений для веб-сайтов на уровне браузера».
Использование Intersection Observer #
Чтобы реализовать полизаполнение для отложенной загрузки элементов <img>
, мы с помощью JavaScript проверяем, находятся ли эти элементы в области просмотра. Если это так, их атрибуты src
(а иногда и srcset
) заполняются URL-адресами с нужными изображениями.
Если вы уже писали код с отложенной загрузкой, вы могли воспользоваться обработчиками событий, такими как scroll
или resize
. Хотя этот подход имеет наибольшую кроссбарузерную совместимость, современные браузеры предлагают более производительный и эффективный способ проверки видимости элементов с помощью API Intersection Observer.
Intersection Observer легче использовать и читать, чем код, основанный на различных обработчиках событий, потому что вам нужно только зарегистрировать наблюдателя (observer) для наблюдения за элементами, а не писать утомительный код обнаружения видимости элементов. Осталось только решить, что делать, когда элемент виден. Давайте примем следующий базовый шаблон разметки для элементов <img>
с отложенной загрузкой:
<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load-1x.jpg" data-srcset="image-to-lazy-load-2x.jpg 2x, image-to-lazy-load-1x.jpg 1x" alt="I'm an image!">
Вам следует сосредоточить внимание на трех важных составляющих этой разметки:
- Атрибут
class
, с помощью которого вы будете выбирать элемент в JavaScript. - Атрибут
src
, ссылающийся на изображение-заполнитель, которое появится при первой загрузке страницы. - Атрибуты
data-src
иdata-srcset
, которые представляют собой атрибуты-заполнители, содержащие URL-адрес изображения, которое будет загружено, когда элемент окажется в области просмотра.
Теперь давайте посмотрим, как использовать Intersection Observer в JavaScript для отложенной загрузки изображений с помощью этого шаблона разметки:
document.addEventListener("DOMContentLoaded", function() {
var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
if ("IntersectionObserver" in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// Possibly fall back to event handlers here
}
});
При обнаружении события DOMContentLoaded
этот сценарий запрашивает DOM для всех элементов <img>
с классом lazy
. Если Intersection Observer доступен, создайте нового наблюдателя, который запускает обратный вызов, когда элементы img.lazy
входят в область просмотра.
Intersection Observer поддерживается почти всеми современными браузерами. Поэтому использование его в качестве полизаполнения для loading="lazy"
сделает отложенную загрузку доступной для большинства посетителей. Intersection Observer недоступен в Internet Explorer. Если поддержка в Internet Explorer очень важна, читайте дальше.
Использование обработчиков событий для реализации поддержки в Internet Explorer #
Если для вашего приложения кроссбраузерная совместимость является критичной, то обязательного использования Intersection Observer для отложенной загрузки будет недостаточно. Вы можете использовать полизаполнение вместе с Intersection Observer (это самое простое решение), но также можно применить код, использующий обработчики событий scroll
, resize
и, возможно, orientationchange
в сочетании с getBoundingClientRect
, чтобы определить, находится ли элемент в области просмотра.
Этот пример Glitch использует getBoundingClientRect
(шаблон разметки остался прежним) в обработчике события scroll
, чтобы проверить, находится ли какой-либо из элементов img.lazy
в области просмотра. Вызов setTimeout
применяется для задержки обработки, а переменная active
содержит состояние обработки, которое используется для ограничения вызовов функций. По мере выполнения отложенной загрузки изображения удаляются из массива элементов. Когда массив элементов достигает значения 0
для свойства length
, код обработчика события прокрутки удаляется.
Хотя этот код работает практически в любом браузере, у него есть потенциальные проблемы с производительностью, поскольку повторяющиеся вызовы setTimeout
могут создавать чрезмерную нагрузку на сеть, даже если их код ограничен. В этом примере проверка выполняется каждые 200 миллисекунд при прокрутке документа или изменении размера окна независимо от того, есть ли изображение в области просмотра. Кроме того, на разработчика возлагается утомительная работа. Ему нужно отследить, сколько элементов осталось для отложенной загрузки. Ему также нужно отменить привязку обработчика событий прокрутки. Подробнее об этой технике читайте в статье «Исчерпывающее руководство по отложенной загрузке изображений».
Проще говоря: используйте отложенную загрузку на уровне браузера с резервной реализацией Intersection Observer везде, где это возможно, и используйте обработчики событий только в том случае, если критически важным требованием приложения является максимально возможная совместимость.
Изображения в CSS #
Хотя теги <img>
являются наиболее распространенным способом размещения изображений на веб-страницах, изображения также можно вызывать с помощью свойства CSS background-image
(и других свойств). Отложенная загрузка на уровне браузера не применяется к фоновым изображениям CSS. Если вам нужно использовать отложенную загрузку для фоновых изображений, рассмотрите другие способы.
В отличие от элементов <img>
, которые загружаются независимо от их видимости, загрузка изображений в CSS выполняется с большим количеством предположений. Когда объектные модели документа и CSS, а также дерево рендеринга уже построены, браузер перед запросом внешних ресурсов проверяет, как CSS-код применяется к документу. Если браузер определяет, что правило CSS, связанное с внешним ресурсом, не применимо к документу в его текущем виде, браузер не запрашивает его.
Это упреждающее поведение можно использовать для отсрочки загрузки изображений в CSS. С помощью JavaScript можно определить, когда элемент находится в области просмотра. Затем нужно применить класс к элементу, который применяет стили, вызывая фоновое изображение. В результате изображение будет загружено в нужный момент, а не при первоначальной загрузке. Например, возьмем элемент, содержащий большое главное фоновое изображение:
<div class="lazy-background">
<h1>Here's a hero heading to get your attention!</h1>
<p>Here's hero copy to convince you to buy a thing!</p>
<a href="/buy-a-thing">Buy a thing!</a>
</div>
Элемент div.lazy-background
обычно содержит главное фоновое изображение, вызываемое CSS-кодом. Однако в этом примере с отложенной загрузкой можно изолировать свойство background-image
элемента div.lazy-background
с помощью класса visible
, добавляемого к элементу, когда он находится в области просмотра:
.lazy-background {
background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}
.lazy-background.visible {
background-image: url("hero.jpg"); /* The final image */
}
Далее с помощью JavaScript проверьте, находится ли элемент в области просмотра (примените Intersection Observer!), и добавьте класс visible
к элементу div.lazy-background
, который загружает изображение:
document.addEventListener("DOMContentLoaded", function() {
var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));
if ("IntersectionObserver" in window) {
let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
lazyBackgroundObserver.unobserve(entry.target);
}
});
});
lazyBackgrounds.forEach(function(lazyBackground) {
lazyBackgroundObserver.observe(lazyBackground);
});
}
});
Но если вам нужна поддержка Internet Explorer для отложенной загрузки фоновых изображений, то придется использовать полизаполнение для кода Intersection Observer, так как Internet Explorer его не поддерживает.
Библиотеки для отложенной загрузки #
Следующие библиотеки можно использовать для отложенной загрузки изображений.
- lazysizes — это полнофункциональная библиотека отложенной загрузки изображений и iframe. Шаблон библиотеки похож на примеры кода, показанные в статье. Дело в том, что шаблон автоматически привязывается к классу
lazyload
в элементах<img>
, и требует, чтобы вы указали URL-адреса изображений в атрибутахdata-src
и/илиdata-srcset
, содержимое которых подменяется в атрибутахsrc
и/илиsrcset
соответственно. Шаблон использует Intersection Observer, для которого можно применить полизаполнение. Кроме того, шаблон можно расширить множеством плагинов, например, для отложенной загрузки видео. Узнайте больше об использовании lazysizes. - vanilla-lazyload — это упрощенный вариант библиотеки для отложенной загрузки изображений, фоновых изображений, видео, востренных фреймов и скриптов. Библиотека использует Intersection Observer, поддерживает адаптивные изображения и обеспечивает отложенную загрузку на уровне браузера.
- lozad.js — еще один упрощенный вариант библиотеки, которая использует только Intersection Observer. Таким образом, она очень эффективна, но ее необходимо сочетать с полизаполнениями, чтобы применять в старых версиях браузеров.
- yall.js — это библиотека, которая использует Intersection Observer и обращается к обработчикам событий. Она совместим с IE11 и основными браузерами.
- Если вам нужна библиотека для отложенной загрузки на React, подумайте о response-lazyload. Несмотря на то, что она не использует Intersection Observer, она предоставляет уже знакомый метод отложенной загрузки изображений для тех, кто привык к разработке приложений на React.