IntersectionObserver: отложенная загрузка с понятным запасным сценарием

2 мин чтения

Загружаем изображения при приближении к экрану через IntersectionObserver и оставляем запасной вариант для старых браузеров.

Изображение загружается перед появлением
  1. Область наблюденияЗадаём запас через rootMargin
  2. ПриближениеIntersectionObserver замечает пересечение
  3. ЗагрузкаНазначаем src и прекращаем наблюдение

На длинной странице нет смысла сразу загружать картинки, до которых читатель ещё не добрался. IntersectionObserver сообщает, когда элемент приближается к видимой области. Используем его для отложенной загрузки, а после загрузки отключим наблюдение. Для браузера без этого API оставим простой запасной вариант.

Наблюдаем только пока это нужно

<img data-src="/images/manual-step.jpg" width="640" height="360"
     alt="Расположение элементов учебной панели">
<script>
const pictures = document.querySelectorAll('img[data-src]');
function loadPicture(image) {
  image.src = image.dataset.src;
  image.removeAttribute('data-src');
}
if (!('IntersectionObserver' in window)) {
  pictures.forEach(loadPicture);
} else {
  const observer = new IntersectionObserver(function (entries) {
    entries.forEach(function (entry) {
      if (!entry.isIntersecting) return;
      loadPicture(entry.target);
      observer.unobserve(entry.target);
    });
  }, { rootMargin: '200px 0px', threshold: 0 });
  pictures.forEach(function (image) { observer.observe(image); });
}
</script>

Положительный rootMargin расширяет область наблюдения по вертикали. Запас в 200 пикселей можно менять под размер картинок, скорость прокрутки и сеть. После назначения src наблюдение конкретной картинки прекращается. Ширина и высота резервируют место, чтобы появление изображения не сдвигало следующие блоки неожиданно. Для содержательных картинок сохраняется осмысленный альтернативный текст.

Совместимость и доступность содержимого

К 2020 году интерфейс есть в основных современных браузерах, но старые клиенты требуют проверки и запасного поведения. Пример загружает всё сразу, если наблюдателя нет; для совсем старого движка дополнительно учитывайте поддержку NodeList.forEach. Также нужна версия содержимого для отключённого JavaScript, например обычная картинка внутри noscript. Первое важное изображение страницы часто разумнее загружать сразу, поскольку задержка может ухудшить восприятие основного материала.

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

Проверяем в ограниченной сети

Откройте панель сети и медленно прокрутите страницу: дальние картинки должны запрашиваться по мере приближения. Вернитесь назад — повторной установки источника быть не должно. Проверьте ошибочный URL, отсутствие API, внутреннюю прокрутку и изменение окна. Даже при отказе загрузки текст и запасной вариант должны сохранять смысл статьи.

Источники и дальнейшее чтение