Gambar statis adalah file yang dipilih saat halaman didesain dan gak berubah, misalnya logo Homestay Kabut atau foto sampul Kamar Teras: ukuran dan rasionya kamu tahu. Gambar dinamis datang dari data, misalnya foto kamar yang di-upload Bu Sri dari HP-nya atau foto profil tamu: ukuran dan rasionya baru ketahuan saat file-nya datang. Bayangin papan foto di lobi homestay. Foto keluarga Bu Sri dibingkai pas dengan ukurannya (statis). Di sebelahnya ada bingkai-bingkai kosong berukuran tetap untuk foto tamu, dan tamu menyelipkan foto apa saja: tegak, mendatar, besar, kecil. Bingkainya yang menentukan ukuran, kelebihan fotonya terselip ke belakang, dan bingkainya sudah tergantung sebelum fotonya datang, jadi foto lain gak perlu digeser.
🧪 Tebakan cepat: Foto Kamar Teras dimuat tanpa
width,height, atauaspect-ratio. Di HP 360 × 640, nama kamar, harga, dan tombol pesan tampil duluan, lalu fotonya datang setinggi 234px dan semuanya terdorong ke bawah. Skor CLS-nya masih "baik" (0,1 ke bawah)? Jawabannya ada di bagian "Siapkan ruangnya: layout shift dan CLS".
Siapkan ruangnya: layout shift dan CLS
Sebelum file gambar datang, browser belum tahu tingginya. Tanpa petunjuk, <img> dianggap setinggi 0px, dan isi di bawahnya langsung ditata. Begitu fotonya datang, semua isi di bawahnya melompat turun. Lompatan ini disebut layout shift, dan kalau terjadi tepat saat tamu mau menekan "Pesan kamar", yang tertekan bisa tombol lain.
CLS (Cumulative Layout Shift) adalah salah satu Core Web Vitals yang mengukur lompatan ini. Menurut web.dev, skor satu lompatan = impact fraction × distance fraction: bagian layar yang kena lompatan, dikali seberapa jauh lompatannya dibanding sisi layar yang terpanjang. Batasnya: 0,1 ke bawah baik, sampai 0,25 perlu perbaikan, di atas 0,25 buruk.
Hitung kartu Kamar Teras di HP 360 × 640. Fotonya selebar 312px, jadi foto 4:3 setinggi 234px. Blok di bawahnya (nama, harga, tombol) setinggi 146px:
- Sebelum foto datang, blok itu di y 16 sampai 162. Sesudahnya, di y 250 sampai 396.
- Impact fraction: dua posisi itu gak bertumpuk, jadi 2 × 146 × 312 = 91.104px² dari 360 × 640 = 230.400px², yaitu 0,395.
- Distance fraction: lompatnya 234px, dibagi sisi terpanjang 640px = 0,366.
- Skornya 0,395 × 0,366 = 0,1446.
Jadi jawaban tebakannya: gak. 0,1446 sudah lewat batas 0,1, masuk "perlu perbaikan". Itu jawaban tebakannya. Ini skor yang dilaporkan Chrome untuk tiap cara, diukur dengan foto yang sengaja datang terlambat:
| Cara menyiapkan ruang | Foto 4:3 (1200 × 900) | Foto tegak 3:4 dari HP Bu Sri (900 × 1200) |
|---|---|---|
| Tanpa ukuran | 0,1446 | 0,2570, buruk |
width="1200" height="900" |
0 | 0,1124 |
aspect-ratio: 4 / 3 + object-fit: cover |
0 | 0 |
Gambar statis: tulis width dan height
<img class="photo" src="kamar-teras-800.jpg" width="1200" height="900" alt="...">
<style>
.photo { display: block; width: 100%; height: auto; }
</style>
- Dari atribut
widthdanheight, browser tahu rasionya 1200 : 900 sebelum file-nya datang, jadi dia menyiapkan kotak 312 × 234px. Atribut itu petunjuk rasio, bukan ukuran tampil. width: 100%danheight: automembuat foto mengikuti lebar kartu dengan rasio yang sama.- Ini cuma benar kalau file-nya memang 4:3. Untuk gambar statis, kamu tahu itu.
Gambar dinamis: kunci kotaknya dengan aspect-ratio dan object-fit
Foto upload Bu Sri bisa tegak, bisa mendatar. Kalau dia upload foto tegak 900 × 1200, kotak 4:3 dari atribut tadi berubah jadi 312 × 416 begitu file-nya datang: lompat lagi, 0,1124. Untuk gambar dinamis, kotaknya yang dikunci:
.photo {
display: block;
width: 100%;
aspect-ratio: 4 / 3; /* kotaknya selalu 4:3, apa pun file-nya */
object-fit: cover; /* isi kotaknya, potong kelebihannya */
background: #e2e8f0; /* warna saat foto belum datang atau gagal */
}
aspect-ratiomenetapkan rasio kotak, jadi tingginya 234px sebelum dan sesudah file datang.object-fitmengatur cara foto mengisi kotak. Bawaan<img>adalahfill: foto ditarik sampai pas, dan foto tegak jadi gepeng.containmemasukkan foto utuh dan menyisakan pita kosong di kiri kanan.covermengisi kotak penuh dan memotong kelebihannya, tanpa distorsi. Untuk kartu kamar,coveryang dipakai.
Ukuran file yang pas: srcset dan sizes
<img class="photo"
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="...">
srcsetmenyebut tiap file dengan lebar aslinya (480wartinya 480 piksel).sizesmemberi tahu browser selebar apa slot fotonya, dari grid di pelajaran grid: 384px di layar 1248px ke atas, sepertiga di 768px ke atas, selebar layar minus 48px di HP.- Layar yang tajam punya DPR (device pixel ratio) 2 atau 3: satu piksel CSS diisi 2 atau 3 piksel layar. Browser memilih file terkecil yang lebarnya minimal slot × DPR. Di Chrome: HP 360 dengan DPR 1 (slot 312) dapat
480w; DPR 2 (perlu 624) dapat800w; DPR 3 (perlu 936) dapat1200w; laptop 1280 dengan DPR 2 (perlu 768) dapat800w.
Lazy loading: cuma untuk yang jauh di bawah
loading="lazy" membuat browser baru memuat gambar saat gambar itu mendekati layar. Cocok untuk foto Kamar Kebun yang jauh di bawah, atau foto Bu Sri di footer: tamu yang gak scroll gak perlu mengunduhnya. Jangan pasang di foto Kamar Teras yang tampil paling atas, karena di situ lazy cuma menunda gambar yang paling dulu dilihat. Gambar di latihan adalah foto yang letaknya jauh di bawah layar pertama, jadi lazy cocok.
Alt text untuk keputusan memesan
WCAG 1.1.1 meminta setiap gambar yang bermakna punya teks pengganti, alt, yang dibacakan pembaca layar. Tulis apa yang dibutuhkan tamu untuk memutuskan, bukan nama file:
alt |
Masalahnya |
|---|---|
alt="IMG_2034.jpg" atau alt="foto" |
gak bilang apa-apa |
alt="Kamar Teras" |
mengulang judul kartu |
alt="Kasur double menghadap jendela besar; di luar, Gunung Prau tertutup kabut pagi" |
pas: tamu tahu kasurnya dan pemandangannya |
Gambar yang cuma hiasan diberi alt="" (kosong, tapi ada), jadi pembaca layar melewatinya. Kalau alt gak ada sama sekali, pembaca layar bisa membacakan nama file-nya.
⚠️ Jebakan yang sering ketemu
- Gambar tanpa ukuran. CLS 0,1446 untuk satu foto 4:3, 0,2570 kalau fotonya tegak. Selalu siapkan ruangnya.
widthdanheightuntuk foto upload. Benar untuk file yang kamu tahu; foto tegak Bu Sri tetap melompat (0,1124). Kunci denganaspect-ratio.- Lupa
object-fit: cover. Bawaannyafill, dan foto tegak jadi gepeng di kotak 4:3. loading="lazy"di foto paling atas, danaltyang kosong atau berisi nama file untuk foto yang bermakna.
TL;DR: Gambar statis (logo, foto sampul) ukurannya kamu tahu: tulis width dan height, plus height: auto, supaya browser menyiapkan ruangnya. Gambar dinamis (foto upload, avatar) rasionya gak kamu tahu: kunci kotaknya dengan aspect-ratio: 4 / 3 dan object-fit: cover (mengisi kotak, memotong kelebihan, tanpa distorsi; bawaannya fill yang menarik foto), plus warna latar saat belum datang. Tanpa ruang yang disiapkan, isi di bawah gambar melompat: CLS 0,1446 untuk satu foto 4:3 di HP 360 × 640 (baik itu 0,1 ke bawah). srcset dan sizes membiarkan browser memilih file terkecil yang minimal slot × DPR. loading="lazy" untuk gambar yang jauh di bawah, bukan foto paling atas. alt (WCAG 1.1.1) menulis apa yang dibutuhkan tamu untuk memutuskan; gambar hiasan alt="".