Optimasi gambar artinya mengirim foto sekecil mungkin tanpa beda yang kelihatan di layar, dalam ukuran yang pas untuk layar pembacanya, dan pada waktu yang tepat. Bayangin Bu Sri mengirim foto kamar ke calon tamu lewat kurir yang dibayar per kilo. Dia bisa membungkus lebih rapat (format), mengirim cetakan seukuran bingkai tamunya, bukan seukuran baliho (srcset), mengirim duluan foto yang langsung dipajang di pintu (prioritas), dan menunda album yang belum tentu dibuka (lazy loading).
🧪 Tebakan cepat: HP Pak Hadi lebarnya 375px. Foto Kamar Teras di HP selebar 327px, dan halaman menyediakan tiga file: 480, 800, dan 1200 piksel. Browser mengunduh yang mana? Jawabannya ada di bagian "srcset dan sizes: browser yang memilih".
Empat keputusan untuk satu foto
| Keputusan | Alat | Di halaman kamar Bu Sri |
|---|---|---|
| Format file | <picture> dengan <source type> |
AVIF, lalu WebP, cadangan JPEG |
| Ukuran file | srcset dan sizes |
480, 800, 1200 piksel |
| Kapan dimuat | fetchpriority="high", loading="lazy" |
foto pertama duluan, galeri ditunda |
| Kotak yang tetap | width dan height |
mencegah CLS, dari pelajaran gambar statis |
Format: diukur di foto yang sama
Format lossy (JPEG, WebP, AVIF) membuang detail yang hampir gak terlihat mata supaya file kecil. Format lossless (PNG) menyimpan semua piksel apa adanya. SVG bukan piksel, tapi gambar dari garis dan bentuk yang ditulis sebagai kode, jadi tajam di ukuran berapa pun.
Kami mengompres satu foto asli 1200 × 900 piksel (danau dan gunung, seperti pemandangan dari teras Bu Sri) dengan encoder sungguhan. Kualitas WebP dan AVIF dipilih supaya SSIM-nya (angka 0 sampai 1 yang mengukur kemiripan dengan foto asli; 1 artinya identik) gak lebih rendah dari JPEG. 1 KB = 1.000 byte.
| Format (encoder, setelan) | 1200 × 900 | 800 × 600 | 480 × 360 | SSIM di 1200 |
|---|---|---|---|---|
| PNG (lossless) | 1.483 KB | 669 KB | 244 KB | 1 |
| JPEG (libjpeg-turbo, quality 80) | 148 KB | 71 KB | 28 KB | 0,952 |
| WebP (cwebp, -q 79) | 108 KB (-27%) | 54 KB (-24%) | 22 KB (-22%) | 0,953 |
| AVIF (avifenc, -q 58) | 84 KB (-43%) | 43 KB (-39%) | 18 KB (-37%) | 0,954 |
- Studi Google mengukur WebP 25 sampai 34% lebih kecil dari JPEG di SSIM yang sama. Foto kita 22 sampai 27%, jadi angkanya mirip.
- AVIF paling kecil: 37 sampai 43% lebih kecil dari JPEG. Semua browser utama mendukungnya sejak Edge 121 (Januari 2024); Chrome sejak 85, Firefox sejak 93, Safari iOS sejak 16.
- PNG 10 kali lebih besar dari JPEG untuk foto. PNG cocok untuk screenshot dan gambar bergaris tajam yang gak boleh berubah satu piksel pun.
- Logo dan ikon pakai SVG. Logo Homestay Kabut sebagai SVG cuma 195 byte dan tajam di semua ukuran; sebagai PNG 96 × 96 piksel 1.128 byte, dan harus dibuat ulang untuk tiap ukuran.
Supaya browser lama tetap dapat gambar, pakai <picture>:
<picture>
<source type="image/avif" srcset="kamar-teras-1200.avif">
<source type="image/webp" srcset="kamar-teras-1200.webp">
<img src="kamar-teras-1200.jpg" width="1200" height="900" alt="Kamar Teras: kasur dobel dan jendela ke arah gunung">
</picture>
- Browser membaca
<source>dari atas dan memakai yang pertama dengantypeyang dia kenal. Browser yang kenal AVIF berhenti di baris pertama. <img>wajib ada: dia cadangan untuk browser lama, dan tempatalt,width,height,loading, danfetchpriorityditulis.<source>cuma menukar file-nya.
srcset dan sizes: browser yang memilih
Layar HP sekarang punya DPR (device pixel ratio) 2 atau 3: tiap 1px CSS digambar dengan 2 atau 3 titik layar. Foto selebar 327px CSS di HP DPR 3 butuh 327 × 3 = 981 titik supaya tajam. Laptop biasa (DPR 1) cukup 384 titik. Satu file untuk semua berarti HP dapat foto buram, atau laptop mengunduh foto yang terlalu besar.
<img
src="kamar-teras-800.jpg"
srcset="kamar-teras-480.jpg 480w, kamar-teras-800.jpg 800w, kamar-teras-1200.jpg 1200w"
sizes="(min-width: 1248px) 384px, (min-width: 768px) calc((100vw - 96px) / 3), calc(100vw - 48px)"
width="1200" height="900" alt="Kamar Teras: kasur dobel dan jendela ke arah gunung">
srcsetadalah daftar file.480wartinya "file ini lebarnya 480 piksel".sizesmemberi tahu lebar slot foto di layar, sebelum CSS dimuat. Angkanya dari grid 12 kolom: 384px di container penuh, sepertiga lebar layar dikurangi gap di tablet, dan lebar layar dikurangi padding 48px di HP. Kondisi dibaca dari kiri; yang pertama cocok dipakai.- Browser menghitung slot × DPR, lalu mengambil file terkecil yang cukup.
- Di
<picture>, tiap<source>membawasrcsetdansizes-nya sendiri.
Hasilnya, sama persis di Chromium 147, WebKit 26.4, dan Firefox 146 yang kami uji:
| Layar | Slot foto | × DPR | Butuh | Diunduh | AVIF |
|---|---|---|---|---|---|
| HP 375px, DPR 3 | 327px | × 3 | 981 | 1200w | 84 KB |
| Tablet 768px, DPR 2 | 224px | × 2 | 448 | 480w | 18 KB |
| Laptop 1280px, DPR 1 | 384px | × 1 | 384 | 480w | 18 KB |
| Laptop 1280px, DPR 2 | 384px | × 2 | 768 | 800w | 43 KB |
Jadi jawaban tebakannya: 1200w. 800 piksel gak cukup untuk 981 titik. Itu jawaban tebakannya. Tanpa srcset, laptop biasa ikut mengunduh file 1200 (84 KB) untuk slot yang cuma butuh 480 (18 KB).
LCP: foto pertama harus datang duluan
LCP (Largest Contentful Paint) adalah waktu sampai elemen terbesar di layar pertama selesai tampil; good maksimal 2,5 detik. Di HP, elemen itu foto Kamar Teras.
Kami mengukurnya di Chromium 147: HP 375px DPR 3, jaringan 1,6 Mbps dengan jeda 150 ms (seperti profil Slow 4G Lighthouse), CSS 45 KB, tiga foto kamar, dan galeri 24 foto JPEG 28 KB di bawahnya:
| Halaman | Gambar yang diunduh | LCP |
|---|---|---|
| JPEG, semua gambar dimuat langsung | 27 (1.121 KB) | 4,19 detik (poor) |
| AVIF, semua gambar dimuat langsung | 27 (930 KB) | 2,56 detik |
AVIF, galeri dan kamar lain loading="lazy" |
13 (535 KB) | 1,11 detik (good) |
AVIF, foto Kamar Teras juga loading="lazy" |
13 (535 KB) | 2,86 detik |
Bandwidth dibagi ke semua gambar yang sedang diunduh. Makin sedikit yang ikut berebut, makin cepat foto pertama tiba.
fetchpriority="high" adalah petunjuk ke browser bahwa gambar ini penting. Di uji kami efeknya kecil (1,12 detik), karena foto Kamar Teras sudah paling awal di HTML dan Chrome sudah menaikkan prioritas gambar yang ada di layar. Di halaman yang lebih ramai efeknya bisa besar: web.dev mencatat LCP Google Flights turun dari 2,6 ke 1,9 detik. Pasang di satu gambar saja, gambar LCP-nya.
Lazy-load cuma di bawah lipatan
Lipatan (the fold) adalah tepi bawah layar pertama, sebelum di-scroll. loading="lazy" menyuruh browser menunda unduhan sampai gambarnya mendekati layar.
<img src="galeri-sikunir.jpg" width="480" height="360" loading="lazy" alt="Matahari terbit di Bukit Sikunir">
- Seberapa dekat, browser yang menentukan. Chromium mulai saat gambar 1.250px dari layar di koneksi cepat, 2.500px di koneksi lambat. Di uji kami (HP 375px, galeri mulai 1.406px dari atas), WebKit dan Firefox gak mengunduh satu pun dari 24 foto galeri sebelum halaman di-scroll.
widthdanheighttetap wajib, supaya kotaknya sudah ada sebelum fotonya datang.- Gambar lazy baru diminta setelah browser tahu letaknya, yaitu setelah CSS dimuat dan layout dihitung. Untuk foto di layar pertama, itu artinya terlambat: 1,11 jadi 2,86 detik di tabel tadi.
⚠️ Jebakan yang sering ketemu
- PNG untuk foto. 1.483 KB, 7,2 detik di jaringan 1,6 Mbps. Pakai AVIF atau WebP dengan cadangan JPEG.
loading="lazy"di semua gambar. Foto pertama ikut ditunda, dan LCP naik 1,7 detik. Lazy cuma untuk yang di bawah lipatan.srcsettanpasizes. Browser menganggap slotnya selebar layar (100vw), jadi laptop 1280px mengunduh file 1200 untuk slot 384px.fetchpriority="high"di banyak gambar. Kalau semuanya penting, gak ada yang didahulukan.
TL;DR: Pilih format dengan mengukur: di foto 1200 × 900 yang sama, JPEG 148 KB, WebP 108 KB, AVIF 84 KB, PNG 1.483 KB; Google mengukur WebP 25 sampai 34% lebih kecil dari JPEG. Logo dan ikon pakai SVG. Tulis <picture> dengan <source type="image/avif">, <source type="image/webp">, lalu <img> JPEG sebagai cadangan. srcset mendaftar file (480w, 800w, 1200w), sizes memberi lebar slot, dan browser mengambil file terkecil yang cukup untuk slot × DPR: HP 375px DPR 3 mengambil 1200w, laptop biasa 480w. Foto LCP dimuat langsung, boleh fetchpriority="high", jangan pernah lazy; gambar di bawah lipatan pakai loading="lazy" dengan width dan height. Di uji kami, LCP HP turun dari 4,19 detik (JPEG, semua langsung) ke 1,11 detik (AVIF, galeri lazy).