Lazy loading obrazów: 5 metod na szybsze ładowanie strony

Lazy loading obrazów: 5 metod na szybsze ładowanie strony

Obrazy to jeden z najpopularniejszych typów treści w sieci, więc czas ładowania strony bardzo łatwo wymyka się spod kontroli.

Nawet dobrze zoptymalizowane obrazy potrafią sporo ważyć. Odbija się to na czasie, jaki odwiedzający muszą odczekać, zanim dotrą do treści twojej witryny. Jest duża szansa, że stracą cierpliwość i pójdą gdzie indziej, chyba że znajdziesz sposób ładowania obrazów, który nie psuje odczuwanej szybkości strony.

W tym artykule poznasz pięć podejść do lazy loadingu obrazów. Możesz dorzucić je do swojego zestawu narzędzi do optymalizacji i poprawić w ten sposób komfort korzystania z witryny.

Czym jest lazy loading?

Lazy loading obrazów polega na ładowaniu ich asynchronicznie, czyli po tym, jak wczyta się treść znajdująca się wyżej, albo wręcz warunkowo: dopiero wtedy, gdy obraz pojawi się w oknie przeglądarki. Oznacza to, że jeśli użytkownik nie przewinie strony do końca, obrazy z dołu w ogóle się nie załadują.

Sporo witryn korzysta z tego podejścia, ale najlepiej widać je w serwisach naładowanych zdjęciami. Wejdź na swoje ulubione łowisko fotografii w wysokiej rozdzielczości, a szybko zauważysz, że strona ładuje tylko ograniczoną liczbę obrazów. W miarę przewijania zobaczysz, jak obrazy zastępcze błyskawicznie wypełniają się prawdziwymi zdjęciami. Zwróć uwagę choćby na ładowanie w Unsplash.com: przewinięcie strony do danego fragmentu wyzwala podmianę placeholdera na zdjęcie w pełnej rozdzielczości.

Dlaczego lazy loading obrazów jest wart uwagi?

Są co najmniej dwa dobre powody, dla których warto rozważyć leniwe ładowanie obrazów na swojej stronie:

  • Jeśli twoja witryna używa JavaScriptu do wyświetlania treści albo udostępniania jakiejkolwiek funkcjonalności, czas ładowania DOM-u szybko staje się krytyczny. Skrypty zwykle czekają z uruchomieniem, aż DOM załaduje się w całości. Na stronie z dużą liczbą obrazów lazy loading, czyli asynchroniczne ładowanie obrazów, może przesądzić o tym, czy użytkownicy zostaną, czy wyjdą.
  • Ponieważ większość rozwiązań lazy loadingu ładuje obraz dopiero wtedy, gdy użytkownik przewinie stronę do miejsca, w którym obraz byłby widoczny w viewporcie, obrazy, do których nikt nie dotrze, nigdy się nie załadują. To spora oszczędność transferu, za którą podziękuje ci większość użytkowników, zwłaszcza tych na urządzeniach mobilnych i wolnych łączach.

Lazy loading obrazów pomaga wydajności witryny, ale jak zabrać się do niego najlepiej?

Idealnej metody nie ma.

Jeśli żyjesz i oddychasz JavaScriptem, napisanie własnego rozwiązania nie powinno być problemem. Nic nie daje większej kontroli niż kod, który napiszesz sam.

Możesz też przeczesać sieć w poszukiwaniu sprawdzonych podejść i zacząć z nimi eksperymentować. Ja tak zrobiłem i trafiłem na pięć ciekawych technik.

#1 Natywny lazy loading

Natywne leniwe ładowanie obrazów i ramek iframe jest świetne. Trudno o coś prostszego niż poniższy kod:

markup
<img src="myimage.jpg" loading="lazy" alt="..." />
<iframe src="content.html" loading="lazy"></iframe>

Jak widzisz, nie ma tu JavaScriptu ani dynamicznej podmiany atrybutu src obrazów i ramek iframe, to zwykły, stary HTML.

Atrybut loading pozwala odłożyć ładowanie obrazów i ramek iframe spoza ekranu do chwili, w której użytkownik do nich doprzewija. loading przyjmuje jedną z trzech wartości:

  • lazy: dokładnie to, czego potrzeba przy lazy loadingu
  • eager: każe przeglądarce załadować wskazaną treść natychmiast.
  • auto: zostawia przeglądarce decyzję, czy ładować leniwie.

Ta metoda nie ma rywali: zero narzutu, czysto i prosto. Choć w chwili pisania tego tekstu większość głównych przeglądarek ma dobre wsparcie dla atrybutu loading, wciąż nie wszystkie są na pokładzie.

#2 Lazy loading z API Intersection Observer

API Intersection Observer to nowoczesny interfejs, którego możesz użyć do leniwego ładowania obrazów i innych treści.

Tak przedstawia to API dokumentacja MDN:

API Intersection Observer pozwala asynchronicznie obserwować zmiany przecięcia elementu docelowego z elementem nadrzędnym albo z widocznym obszarem dokumentu najwyższego poziomu.

Innymi słowy: asynchronicznie obserwowane jest przecięcie jednego elementu z drugim.

Załóżmy, że chcesz leniwie ładować galerię zdjęć. Kod pojedynczego obrazu wyglądałby tak:

markup
<img data-src="image.jpg" alt="test image">

Zauważ, że ścieżka do obrazu siedzi w atrybucie data-src, a nie w src. Powód jest prosty: src oznaczałby, że obraz ładuje się natychmiast, a nie o to nam chodzi.

W CSS-ie nadajesz każdemu obrazowi min-height, powiedzmy 100px. Dzięki temu każde miejsce na obraz (element img bez atrybutu src) ma jakąś wysokość:

css
img {
min-height: 100px;
/* więcej stylów tutaj */
}

W pliku JavaScript tworzysz następnie obiekt config i rejestrujesz go w instancji intersectionObserver:

javascript
// tworzymy obiekt konfiguracji: rootMargin i threshold
// to dwie właściwości udostępniane przez interfejs
const config = {
  rootMargin: '0px 0px 50px 0px',
  threshold: 0
};

// rejestrujemy obiekt config w instancji
// intersectionObserver
let observer = new intersectionObserver(function(entries, self) {
// iterujemy po każdym wpisie
  entries.forEach(entry {
    // obsługujemy tylko obrazy, które się przecinają.
    // isIntersecting to właściwość udostępniana przez interfejs
if(entry.isIntersecting) {
    /. / Fonction personnalisée qui copie le chemin vers l'image
      // z data-src do src
preloadImage(entry.target);
      // obraz jest już na miejscu, przestajemy obserwować
      self.unobserve(entry.target);
}
});
}, config);

Na koniec przechodzisz po wszystkich obrazach i dodajesz je do tej instancji iterationObserver:

javascript
const imgs = document.querySelectorAll('[data-src]');
imgs.forEach(img {
  observer.observe(img);
});

Zalety tego rozwiązania: łatwo je wdrożyć, jest wydajne, a całe liczenie zostawia po stronie intersectionObserver.

Z drugiej strony, choć najnowsze wersje większości przeglądarek obsługują API Intersection Observer, nie robią tego wszystkie. Na szczęście polyfill jest dostępny.

#3 Lozad.js – Lazyload js

Szybka i łatwa alternatywa dla własnej implementacji to zrzucenie całej roboty na bibliotekę JS.

Lozad to bardzo wydajny, lekki i konfigurowalny lazy loader napisany w czystym JavaScripcie, bez żadnych zależności. Użyjesz go do leniwego ładowania obrazów, wideo, ramek iframe i nie tylko, a pod spodem korzysta z API Intersection Observer.

Lozada dołączysz przez npm/Yarn i zaimportujesz bundlerem, którego akurat używasz:

bash
npm install --save lozad

yarn add lozad
javascript
import lozad from 'lozad';

Możesz też pobrać bibliotekę z CDN-u i wstawić ją na dole strony HTML w znaczniku < script>:

markup
<script src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>

Następnie, w najprostszym wariancie, dodaj w kodzie klasę lozad do zasobu:

markup
<img class="lozad" data-src="img.jpg">

Na koniec utwórz instancję Lozada w swoim pliku JS:

javascript
const observer = lozad();
observer.observe();

Wszystkie szczegóły użycia biblioteki znajdziesz w repozytorium Lozada na GitHubie.

Jeśli nie chcesz zagłębiać się w mechanikę API Intersection Observer albo po prostu szukasz szybkiego wdrożenia obsługującego różne typy treści, Lozad jest świetnym wyborem.

Pamiętaj tylko o wsparciu przeglądarek i w razie potrzeby dołóż do biblioteki polyfill dla API Intersection Observer.

#4 Lazy loading z efektem rozmytego obrazu

Najpierw widzisz rozmytą kopię obrazu w niskiej rozdzielczości, a w tle leniwie ładuje się wersja w wysokiej rozdzielczości:

Rozmyty obraz zastępczy w serwisie Medium
Rozmyty obraz zastępczy w serwisie Medium
Obraz w wysokiej rozdzielczości ładowany leniwie w serwisie Medium.
Obraz w wysokiej rozdzielczości, ładowany leniwie, w serwisie Medium.

Obrazy z takim efektem rozmycia można ładować leniwie na kilka sposobów.

Oto wszystkie zalety tego rozwiązania:

  • Wydajność: raptem 463 bajty kodu CSS i 1 007 bajtów zminifikowanego JavaScriptu.
  • Obsługa ekranów retina
  • Brak zależności: nie potrzebujesz jQuery ani innych bibliotek czy frameworków.
  • Progressive enhancement na starsze przeglądarki i na sytuacje, w których JavaScript zawiedzie.

Żeby uzyskać taki efekt, możesz pobrać progressive-image.js.

#5 Yall.js – Lazyload js

Yall to rozbudowany skrypt lazy loadingu dla obrazów, wideo i ramek iframe. Korzysta z API Intersection Observer, a tam gdzie trzeba, sprytnie schodzi do klasycznej obsługi zdarzeń.

Po dołączeniu Yall do dokumentu trzeba go zainicjalizować w ten sposób:

javascript
<script src="yall.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", yall);
</script>

Następnie, żeby leniwie załadować zwykły img, w kodzie wystarczy tyle:

markup
<img class="lazy" src="placeholder.jpg" data-src="image-to-lazy-load.jpg" alt="Alternative text to describe image.">

Zwróć uwagę na trzy rzeczy:

  • do elementu dodajesz klasę lazy
  • wartością src jest obraz zastępczy
  • ścieżka do obrazu, który ma być ładowany leniwie, siedzi w atrybucie data-src

Do zalet Yall należą:

  • wysoka wydajność dzięki API Intersection Observer
  • świetne wsparcie przeglądarek (sięga aż do IE11)
  • brak dodatkowych zależności

Więcej o możliwościach Yall i o bardziej złożonych wdrożeniach przeczytasz na GitHubie.

Podsumowanie

I to tyle, pięć metod leniwego ładowania obrazów, z którymi możesz zacząć eksperymentować i testować je w swoich projektach.

CSSHTML

Damien Flandrin Web developer od 2010 roku, twórca Gekkode i Email Impact. Każdy artykuł jest sprawdzany na prawdziwym projekcie przed publikacją. Kontakt
Newsletter

Nowe testy, poradniki i projekty — e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.