Lazy Loading на самом деле не совсем Lazy

На сайте подключена библиотека для ленивой загрузки изображений (Lazy Loading).
Таких js-библиотек достаточное количество на github-е. Вот одна из популярных.
Как правило, для задействования либы требуется:
a) — наличие у тега img определенного класса
b) — наличие у тега img атрибута data-original (или data-src) c указанием ссылки на изображения.
Примерно так:
<img data-original="site.com/uploads/.../img.jpg"/>

Атрибут src может быть не задан вовсе, либо в нем должна быть ссылка на «заглушку».
Чтобы не «ковырять» редактор и/или текстовый парсер было решено сделать в js так:
$('#content .topic-type-topic img').each(function () {
    $(this).addClass('lazy');
    $(this).attr('data-original', $(this).attr('src'));
    $(this).removeAttr('src');
});

$("img.lazy").lazyload({
    effect: "fadeIn"
});

После этого все работает, картинки подгружаются при скролле, по крайней мере визуально.

Недавно заглянул в консоль и увидел, что картинки при загрузке страницы все равно загружаются все разом, а эффект ленивой подгрузки лишь визуальный, т.к. никакой экономии трафика не происходит. Причина загрузки всех изображений в том, что обработка атрибутов тега img происходит ПОСЛЕ загрузки дерева DOM, в частности после загрузки всех картинок и jQuery.

В идеале конечно обработать img в самом движке — добавить правила Jevix, подправить редактор и/или текстовый парсер, затем все имеющиеся топики прогнать через все это.
Можно ли обработать тег img на лету до загрузки страницы? (через модуль Viewer?)

Гугл предложил еще вариант — заменить js-обработку тега img с jQuery на чистый JavaScript и вставить её в head. Кто знает как это сделать — прошу помочь, а я протестирую этот вариант.

6 комментариев

avatar
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <script>
  //  Селектор для узконаправленного применения,
  //  например внутри поста
  let imgSelector = '.post__content img';

  window.addEventListener("DOMContentLoaded", () => {      
    let images = document.querySelectorAll(imgSelector);

    images.forEach( (element) => {
      let imgSrc = element.getAttribute('src');
      element.removeAttribute('src');
      element.setAttribute('data-src', imgSrc);
    })
  });
 </script>
</head>
<body>
  <div class="post__content">
    <img src="//via.placeholder.com/200x200/" alt="" class="lazyload">
    <img src="//via.placeholder.com/300x300/" alt="" class="lazyload">
  </div>
  <img src="//via.placeholder.com/100x100/" alt="">

  <!-- Пример скрипта из твоего поста -->
  <script src="https://cdn.jsdelivr.net/npm/lazyload@2.0.0-rc.2/lazyload.js"></script>
  <script>
      let images = document.querySelectorAll(imgSelector);
      lazyload(images);
  </script>
</body>
</html>
  • dex-
  • 0
avatar
Насчет DOMContentLoaded можете почитать по ссылке. Картинки при DOMContentLoaded не будут загружены, а уйдут в canceled, потому что при load у них уже не будет src.
avatar
Наличие класса «lazyload» на примере не обязательно. Выборка производится селектором imgSelector
avatar
Использую браузер Vivaldi (Chromium-based).
Как это ни парадоксально — но картинки все равно грузятся. Скрипт вроде отрабатывает. Я даже попробовал не подключать lazyload(images); — и даже в этом случае они грузятся, хоть и не отображаются (т.к. у них уже нет src).
Хотя описание DOMContentLoaded говорить об обратном ¯\_(ツ)_/¯


Попробовал другие браузеры (все последних версий):
Firefox — картинки грузятся сразу
Chrome — картинки грузятся сразу
Opera — картинки грузятся сразу
MS Edge — и о чудо! Все отработало как надо!


Видимо браузеры «чудят»…
avatar
И, кстати, залогиниться сюда удалось только через edge ;)
avatar
Код рабочий. Проверено на Chrome и Firefox.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.