Lazy Loading — Performance

Lazy Loading Lazy loading berarti menunda pemuatan resource sampai resource tersebut benar-benar dibutuhkan. Ini mengurangi initial page load secara…

Lazy loading artinya menunda mengunduh sesuatu sampai benar-benar mau dilihat. Gambar dan iframe yang jauh di bawah layar pertama gak ikut diunduh waktu halaman dibuka, tapi menunggu sampai kamu scroll mendekatinya. Mirip pelayan restoran yang menyajikan hidangan berikutnya waktu kamu hampir selesai makan, bukan semua sekaligus di awal sampai mejanya penuh. Hidangan pembuka tetap harus datang paling dulu.

🧪 Tebakan cepat: halaman portofolio-mu punya satu foto sampul (hero) di paling atas dan enam foto galeri di bawah. Kalau ketujuh gambar itu kamu kasih loading="lazy", LCP-nya jadi lebih cepat, sama, atau lebih lambat? Tebak dulu, jawabannya ada di bagian "Jangan lazy gambar paling atas".

Satu atribut: loading="lazy"

Gak perlu JavaScript. Cukup satu atribut di tag <img> atau <iframe>, dan semua browser modern mengerti. Ini halaman portofolio di Lab:

<h1>My Portfolio</h1>

<!-- Hero: langsung terlihat, jadi TANPA lazy -->
<img id="hero" src="hero.jpg" width="1200" height="900"
     fetchpriority="high" alt="Sampul portofolio">

<!-- Galeri: jauh di bawah, jadi lazy -->
<div class="gallery-section">
  <img class="gallery" src="karya-1.jpg" loading="lazy"
       width="800" height="600" alt="Karya pertama">
  <img class="gallery" src="karya-2.jpg" loading="lazy"
       width="800" height="600" alt="Karya kedua">
  <img class="gallery" src="karya-3.jpg" loading="lazy"
       width="800" height="600" alt="Karya ketiga">
</div>

<!-- Peta: iframe juga bisa lazy -->
<iframe src="map.html" loading="lazy" width="600" height="400"
        title="Peta lokasi"></iframe>

Di Lab, enam foto galeri masing-masing 80 KB, hero 180 KB, dan peta sekitar 600 KB. Tanpa lazy, browser mengunduh 1.260 KB begitu halaman dibuka. Dengan lazy di galeri dan peta, cuma 340 KB.

Kapan browser mulai mengunduh

Lazy bukan berarti "baru diunduh saat kelihatan". Chrome mulai mengunduh begitu jarak elemennya ke bawah layar tinggal 1.250 px (koneksi cepat seperti 4G) atau 2.500 px (koneksi lambat), supaya gambarnya sudah siap waktu kamu sampai.

Di Lab, layar HP-nya setinggi 640 px, jadi batasnya 640 + 1.250 = 1.890 px dari atas halaman:

Elemen Posisi atas Mulai diunduh
karya-1 1.580 px langsung saat dibuka (di bawah 1.890)
karya-2 1.842 px langsung saat dibuka
karya-3 2.104 px setelah scroll 214 px
karya-6 2.890 px setelah scroll 1.000 px
peta 3.300 px setelah scroll 1.410 px

Rumusnya: posisi atas dikurangi tinggi layar dikurangi 1.250. Karena itu 340 KB tadi berisi hero plus karya-1 dan karya-2.

Jangan lazy gambar paling atas

Gambar yang langsung terlihat saat halaman dibuka (sering disebut above the fold, di atas garis lipatan layar) biasanya jadi elemen LCP (Largest Contentful Paint), elemen terbesar di layar pertama. Kalau dia lazy, browser gak boleh mengunduhnya sebelum tahu posisinya, jadi harus menunggu CSS selesai dan layout dihitung. Waktu yang tadinya bisa dipakai mengunduh jadi terbuang.

Di Lab: hero tanpa lazy, LCP 1,5 detik. Hero diberi lazy, LCP jadi 1,9 detik. Jadi kalau ketujuh gambar diberi lazy, LCP-nya lebih lambat. Itu jawaban tebakannya.

Untuk gambar LCP, lakukan kebalikannya: tambahkan fetchpriority="high". Browser langsung memberinya prioritas High di antrean unduhan, bukan menunggu sampai tahu gambar itu terlihat. Di Lab, kalau galerinya gak lazy, enam foto galeri berebut koneksi dengan hero dan LCP jadi 1,8 detik. Dengan fetchpriority="high" di hero, LCP balik ke 1,5 detik.

Menunda hal lain: IntersectionObserver

loading="lazy" cuma untuk <img> dan <iframe>. Untuk menunda hal lain, misalnya komponen komentar atau data dari API, pakai IntersectionObserver: dia memanggil function-mu saat sebuah elemen mendekati layar.

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {          // elemennya sudah dekat layar
      muatKomentar(entry.target);        // baru ambil datanya sekarang
      observer.unobserve(entry.target);  // cukup sekali
    }
  });
}, { rootMargin: '200px' });             // mulai 200 px sebelum terlihat

observer.observe(document.querySelector('#komentar'));

⚠️ Jebakan yang sering ketemu

TL;DR: loading="lazy" di <img> dan <iframe> menunda unduhan sampai elemennya mendekati layar (di Chrome: 1.250 px di koneksi cepat, 2.500 px di koneksi lambat). Di Lab, unduhan awal turun dari 1.260 KB ke 340 KB. Pasang di semua gambar galeri dan iframe yang jauh di bawah, lengkap dengan width dan height. Jangan pernah di gambar paling atas: hero yang lazy membuat LCP naik dari 1,5 ke 1,9 detik. Hero justru diberi fetchpriority="high". Untuk menunda hal lain, pakai IntersectionObserver.

Yang akan kamu pelajari