Leniwe ładowanie obrazów

Obrazy mogą pojawiać się na stronie internetowej, jeśli są wbudowane w kodzie HTML jako elementy <img> lub jako obrazy tła CSS. Z tego posta dowiesz się, jak leniwie ładować oba typy obrazów.

Obrazy w treści

Najczęściej są to obrazy używane w elementach <img>. W przypadku obrazów w tekście dostępne są 3 opcje leniwego ładowania, których można użyć w połączeniu, aby uzyskać największą zgodność w różnych przeglądarkach:

Korzystanie z leniwego ładowania na poziomie przeglądarki

Zarówno Chrome, jak i Firefox obsługują leniwe ładowanie z atrybutem loading. Ten atrybut można dodawać do elementów <img> oraz <iframe>. Wartość lazy informuje przeglądarkę, że ma ona wczytywać obraz w widocznym obszarze i pobierać inne obrazy, gdy użytkownik znajdzie się w pobliżu.

Szczegółowe informacje o obsłudze przeglądarek znajdziesz w polu loading tabeli zgodności przeglądarek w MDN. Jeśli przeglądarka nie obsługuje leniwego ładowania, atrybut zostanie zignorowany, a obrazy wczytają się od razu, jak zwykle.

W większości witryn dodanie tego atrybutu do obrazów w tekście zwiększa wydajność i oszczędza użytkowników wczytujących obrazy, których nigdy nie przewijali. Jeśli masz dużą liczbę obrazów i chcesz mieć pewność, że użytkownicy przeglądarek nieobsługujących funkcji leniwego ładowania musisz połączyć to działanie z jedną z metod opisanych poniżej.

Więcej informacji znajdziesz w artykule Leniwe ładowanie stron w przeglądarce na poziomie przeglądarki.

Korzystanie z obserwatora skrzyżowania

Do leniwego ładowania elementów <img> używamy kodu JavaScript, by sprawdzić, czy znajdują się one w widocznym obszarze. Jeśli tak, atrybuty src (a czasem srcset) są zapełniane adresami URL odpowiednich treści obrazu.

Jeśli masz już wcześniej napisany kod leniwego ładowania, możesz to zrobić, korzystając z modułów obsługi zdarzeń, takich jak scroll lub resize. Ta metoda jest najbardziej zgodna z przeglądarkami, ale nowoczesne przeglądarki pozwalają sprawniej sprawdzać widoczność elementów za pomocą interfejsu Intersection Observer API.

Observer Intersection Observer jest łatwiejszy w użyciu i odczytywaniu niż kod, który bazuje na różnych modułach obsługi zdarzeń, ponieważ do obserwacji elementów wystarczy zarejestrować obserwatora, zamiast pisać uciążliwy kod wykrywania widoczności elementów. Pozostało Ci już tylko zdecydować, co zrobić, gdy element będzie widoczny. Przyjmijmy ten podstawowy wzorzec znaczników w elementach <img> ładowanych z leniwym ładowaniem:

<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!">

Oto 3 istotne elementy tego znacznika, na których warto się skupić:

  1. Jest to atrybut class, który służy do wybierania elementu w JavaScript.
  2. Atrybut src, który odwołuje się do obrazu zastępczego, który wyświetli się po pierwszym wczytaniu strony.
  3. Atrybuty data-src i data-srcset, które są atrybutami zastępczymi zawierającymi adres URL obrazu, który wczytasz, gdy element znajdzie się w widocznym obszarze.

Zobaczmy, jak wykorzystać obserwację intersekcji w JavaScripcie do leniwego ładowania obrazów, korzystając z tego wzorca znaczników:

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
  }
});

Ten skrypt wysyła zapytanie do DOM ze zdarzeniem DOMContentLoaded dokumentu w przypadku wszystkich elementów <img> z klasą lazy. Jeśli obserwator Intersection Observer jest dostępny, utwórz nowego obserwatora, który wywołuje wywołanie zwrotne, gdy elementy img.lazy pojawią się w widocznym obszarze.

Intersection Observer (obserwacja skrzyżowań) jest dostępny we wszystkich nowoczesnych przeglądarkach. Dlatego użycie go jako kodu polyfill dla loading="lazy" sprawi, że leniwe ładowanie będzie dostępne dla większości użytkowników.

Obrazy w CSS

Choć tagi <img> są najpopularniejszym sposobem używania obrazów na stronach internetowych, obrazy można też wywoływać za pomocą właściwości CSS background-image (i innych). Leniwe ładowanie na poziomie przeglądarki nie działa w przypadku obrazów tła CSS, więc jeśli chcesz, by obrazy tła były w nim ładowane, musisz rozważyć inne metody.

W przeciwieństwie do elementów <img>, które ładują się niezależnie od ich widoczności, wczytywanie obrazów w CSS opiera się na większej spekulacji. Po utworzeniu modeli obiektowych dokumentów i CSS oraz drzewa renderowania przeglądarka sprawdza, jak kod CSS jest stosowany w dokumencie, zanim zażąda zasobów zewnętrznych. Jeśli przeglądarka ustali, że reguła CSS dotycząca zasobu zewnętrznego nie ma zastosowania do dokumentu w takiej postaci, nie żąda go.

To zachowanie spekulacyjne można wykorzystać do opóźnienia wczytywania obrazów w CSS. Za pomocą JavaScriptu określa, kiedy element znajduje się w widocznym obszarze, a następnie stosuje do niego klasę, która stosuje styl wywołujący obraz tła. Dzięki temu obraz jest pobierany w czasie, gdy jest potrzebny, a nie przy początkowym wczytywaniu. Weźmy na przykład element, który zawiera duży obraz banera powitalnego:

<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>

Element div.lazy-background normalnie zawieraby główny obraz tła wywoływany przez niektóre CSS. W tym przykładzie z leniwym ładowaniem możesz jednak wyodrębnić właściwość background-image elementu div.lazy-background za pomocą klasy visible dodanej do elementu, gdy jest on w widocznym obszarze:

.lazy-background {
  background-image: url("hero-placeholder.jpg"); /* Placeholder image */
}

.lazy-background.visible {
  background-image: url("hero.jpg"); /* The final image */
}

Tutaj użyj JavaScriptu, by sprawdzić, czy element znajduje się w widocznym obszarze (za pomocą narzędzia Intersection Observer!). Potem do elementu div.lazy-background dodaj klasę visible, która wczytuje obraz:

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);
    });
  }
});

Wpływ na największe wyrenderowanie treści (LCP)

Leniwe ładowanie to doskonała optymalizacja, która zmniejsza zarówno ogólne wykorzystanie danych, jak i rywalizację między siecią podczas uruchamiania, ponieważ opóźnia ładowanie obrazów do czasu, gdy są potrzebne. Może to skrócić czas uruchamiania i skrócić przetwarzanie w wątku głównym dzięki skróceniu czasu potrzebnego na dekodowanie obrazu.

Leniwe ładowanie to jednak technika, która może negatywnie wpływać na największy LCP wyrenderowania treści w Twojej witrynie, jeśli nie chcesz się nią bawić. Jedną z rzeczy, których należy unikać, jest leniwe ładowanie obrazów, które znajdują się w widocznym obszarze podczas uruchamiania.

W przypadku leniwego ładowania opartego na języku JavaScript należy unikać leniwego ładowania obrazów w widocznym obszarze, ponieważ w tych rozwiązaniach często używa się atrybutu data-src lub data-srcset jako obiektów zastępczych atrybutów src i srcset. Problem polega na tym, że wczytywanie tych obrazów będzie opóźnione, ponieważ skaner wstępnego wczytywania przeglądarki nie może ich znaleźć podczas uruchamiania.

Nawet używanie leniwego ładowania na poziomie przeglądarki w celu leniwego ładowania obrazu w widocznej części ekranu może spowodować błąd. Po zastosowaniu elementu loading="lazy" do obrazu w widocznym obszarze będzie on opóźniony, dopóki przeglądarka nie potwierdzi, że znajduje się w tym obszarze, co może wpłynąć na LCP strony.

Nigdy nie używaj leniwego ładowania obrazów, które są widoczne w widocznym obszarze podczas uruchamiania. To wzorzec, który negatywnie wpływa na LCP witryny i w konsekwencji na wrażenia użytkowników. Jeśli potrzebujesz obrazu przy uruchamianiu, nie ładuj go leniwie, ale jak najszybciej.

Biblioteki z leniwym ładowaniem

Leniwe ładowanie powinno być stosowane zawsze, gdy jest to możliwe, ale jeśli nie ma takiej możliwości (np. znaczna grupa użytkowników nadal korzysta ze starszych przeglądarek), do leniwego ładowania obrazów można użyć tych bibliotek:

  • lazysizes to biblioteka, która oferuje leniwe ładowanie obrazów i elementów iframe. Używany przez niego wzorzec jest bardzo podobny do pokazanego tutaj przykładowego kodu, ponieważ automatycznie wiąże się z klasą lazyload w elementach <img>. Wymaga też określenia adresów URL obrazów w atrybutach data-src lub data-srcset, których zawartość jest zamieniana odpowiednio na atrybuty src lub srcset. Wykorzystuje on Intersection Observer (który można wykorzystać przy użyciu kodu polyfill) i można go rozszerzyć za pomocą wtyczek do takich funkcji jak leniwe ładowanie filmów. Więcej informacji o używaniu leniwych rozmiarów
  • vanilla-lazyload to lekka opcja do leniwego ładowania obrazów, obrazów tła, filmów, elementów iframe i skryptów. Wykorzystuje on Intersection Observer, obsługuje elastyczne obrazy i umożliwia leniwe ładowanie na poziomie przeglądarki.
  • lozad.js to inna prostsza opcja, która używa tylko narzędzia Intersection Observer. Jest więc bardzo wydajny, ale trzeba go wypełnić, zanim będzie można użyć go w starszych przeglądarkach.
  • Jeśli potrzebujesz biblioteki leniwego ładowania specyficznej dla React, rozważ użycie react-leniwego ładowania. Choć nie wykorzystuje on Intersection Observer, zapewnia znaną metodę leniwego ładowania obrazów dla osób przyzwyczajonych do tworzenia aplikacji za pomocą React.