вернуться к уроку

Загрузка видимых изображений

важность: 4

Допустим, у нас есть клиент с низкой скоростью соединения, и мы хотим сэкономить его трафик.

Для этого мы решили не показывать изображения сразу, а заменять их на «макеты», как тут:

<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">

То есть, изначально, все изображения – placeholder.svg. Когда страница прокручивается до того положения, где пользователь может увидеть изображение – мы меняем src на значение из data-src, и таким образом изображение загружается.

Вот пример в iframe:

Прокрутите его, чтобы увидеть загрузку изображений «по требованию».

Требования:

  • При загрузке страницы те изображения, которые уже видимы, должны загружаться сразу же, не ожидая прокрутки.
  • Некоторые изображения могут быть обычными, без data-src. Код не должен касаться их.
  • Если изображение один раз загрузилось, оно не должно больше перезагружаться при прокрутке.

P.S. Если можете, реализуйте более продвинутое решение, которое будет загружать изображения на одну страницу ниже/после текущей позиции.

P.P.S. Достаточно обрабатывать вертикальную прокрутку, горизонтальную не требуется.

Открыть песочницу для задачи.

Обработчик onscroll должен проверить, какие изображения видимы, и показать их.

Мы также можем запустить его при загрузке страницы, чтобы сразу обнаружить видимые изображения и загрузить их.

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

Можно разместить его перед закрывающим тегом </body>:

// ...содержимое страницы выше...

function isVisible(elem) {

  let coords = elem.getBoundingClientRect();

  let windowHeight = document.documentElement.clientHeight;

  // верхний край элемента виден?
  let topVisible = coords.top > 0 && coords.top < windowHeight;

  // нижний край элемента виден?
  let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;

  return topVisible || bottomVisible;
}

Функция showVisible() использует проверку на видимость, реализованную в isVisible() для загрузки видимых картинок:

function showVisible() {
  for (let img of document.querySelectorAll('img')) {
    let realSrc = img.dataset.src;
    if (!realSrc) continue;

    if (isVisible(img)) {
      img.src = realSrc;
      img.dataset.src = '';
    }
  }
}

showVisible();
window.onscroll = showVisible;

P.S. В решении этой задачи есть также вариант isVisible, который предварительно загружает изображения, находящиеся в пределах одной страницы выше/ниже от текущей прокрутки документа.

Открыть решение в песочнице.