Gambar Responsif

Atribut srcset dan sizes serta elemen picture untuk art direction.

Daftar isi

Satu berkas gambar untuk semua perangkat memaksa ponsel mengunduh gambar berukuran desktop, atau sebaliknya memaksakan gambar buram pada layar besar. Topik ini membahas atribut srcset dengan deskriptor lebar dan kerapatan, atribut sizes yang memberi tahu ukuran slot tampil, serta elemen picture untuk art direction dan format modern. Setelah mengikuti topik ini, markup gambar yang menyesuaikan diri dengan layar dan kebutuhan piksel dapat disusun.

Masalah satu berkas untuk semua layar#

Penskalaan melalui CSS hanya mengubah ukuran tampil, bukan ukuran berkas yang diunduh. Gambar 1280 piksel yang dipersempit menjadi 320 piksel di layar ponsel tetap membawa seluruh datanya, sehingga ponsel membayar kuota untuk piksel yang tidak pernah terlihat jelas. Arah sebaliknya juga bermasalah, karena gambar kecil yang direnggangkan di layar besar tampak buram.

Beban itu berulang pada setiap kunjungan, karena gambar termasuk aset yang jarang berubah tetapi selalu diminta. Dengan beberapa kandidat berkas gambar, layar kecil membawa berkas yang jauh lebih ringan, sedangkan layar besar tetap menerima versi yang tajam. Efeknya langsung terasa pada kecepatan tampil halaman dan pada kuota yang terpakai.

Kebutuhan piksel juga bukan sekadar lebar slotnya. Layar dengan kerapatan tinggi (device pixel ratio 2) menampilkan slot selebar 400 piksel CSS dengan 800 piksel gambar agar tetap tajam, dan kerapatan 3 menuntut 1200 piksel. Satu berkas tidak mungkin pas untuk semua kombinasi lebar layar dan kerapatan tersebut, sehingga browser perlu diberi beberapa kandidat beserta petunjuk pemilihannya. Dua atribut berikutnya, srcset dan sizes, adalah sarana untuk itu, sedangkan elemen picture menangani kasus yang lebih mendasar ketika komposisi gambarnya sendiri perlu diganti.

srcset dengan deskriptor lebar#

Atribut srcset mendaftar kandidat berkas beserta deskriptor lebar (width descriptor), yaitu angka berakhiran w yang menyatakan lebar asli setiap berkas dalam piksel. Nilai src tetap ditulis sebagai cadangan bagi browser lama yang tidak mengenal srcset. Kandidat pada contoh berikut tersedia dalam tiga lebar, dan tampilannya menggunakan gambar suasana ruang baca.

html Contoh: srcset dengan tiga kandidat
<img
  src="suasana-640.svg"
  srcset="suasana-320.svg 320w, suasana-640.svg 640w, suasana-1280.svg 1280w"
  sizes="(max-width: 600px) 480px, 800px"
  alt="Suasana ruang baca dengan meja, buku, dan lampu"
  width="1280" height="720">

Satu kandidatnya berupa berkas berikut. Dua berkas lainnya disusun dengan pola yang sama, yaitu viewBox dan lebar deklarasi 640 serta 1280 piksel, dengan bentuk-bentuk yang lebih rinci pada versi yang lebih besar.

svg suasana-320.svg
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180" viewBox="0 0 320 180" role="img" aria-labelledby="judul-320">
  <title id="judul-320">Suasana ruang baca, versi sederhana 320 piksel</title>
  <rect width="320" height="180" fill="#e3f2fd"/>
  <rect y="130" width="320" height="50" fill="#a1887f"/>
  <rect x="60" y="92" width="200" height="38" rx="5" fill="#8d6e63"/>
  <rect x="92" y="62" width="58" height="32" rx="3" fill="#ffffff" stroke="#90a4ae"/>
  <circle cx="244" cy="52" r="15" fill="#fff59d" stroke="#f9a825" stroke-width="3"/>
</svg>

Deskriptor w wajib menyatakan lebar asli berkas dengan benar, karena angka itulah yang dibandingkan browser dengan kebutuhan pikselnya. Apabila srcset menggunakan deskriptor w, atribut sizes menjadi wajib menyertainya, sebagaimana diuraikan pada bagian berikut.

Urutan kandidat pada srcset tidak menentukan hasilnya, karena browser mengurutkannya sendiri menurut kebutuhan yang dihitung. Browser juga bebas menyimpang dari pilihan matematisnya, misalnya menggunakan kandidat yang sudah tersimpan dalam cache atau menghemat kuota, sehingga hasilnya dapat berbeda antarbrowser. Selama setiap kandidat membawa deskriptor yang benar, penyimpangan semacam itu tetap menghasilkan gambar yang layak tampil.

Cara browser memilih kandidat#

Atribut sizes memberi tahu lebar slot yang akan ditempati gambar, sehingga browser dapat menghitung kebutuhan piksel sebelum mengunduh apa pun. Nilainya berupa daftar kondisi media beserta lebar slotnya, dan kondisi pertama yang cocok yang digunakan. Browser kemudian mengalikan lebar slot itu dengan kerapatan perangkat, lalu memilih kandidat srcset terkecil yang memenuhi kebutuhan tersebut. Diagram berikut merangkum alurnya.

Browser menghitung kebutuhan piksel lalu memilih kandidat srcset terkecil yang cukup besarBaca sizes dan lebar layarTentukan lebar slot dari kondisi mediaHitung kebutuhan piksel (slot × kerapatan)Pilih kandidat terkecil yang cukup besartak cukupkandidat terbesar dipakai
Alur browser menghitung kebutuhan piksel dan memilih kandidat srcset

Simulasi berikut menjalankan alur yang sama tanpa browser, dengan lebar layar 420 piksel CSS dan kerapatan 2, sehingga hasil pemilihannya dapat diperiksa angka demi angka.

js Simulasi pemilihan kandidat srcset
// simulasi pemilihan kandidat srcset oleh browser
const kandidat = [320, 640, 1280];
const dpr = 2;
const lebarLayar = 420; // piksel CSS pada layar yang dipakai
const sizes = "(max-width: 600px) 480px, 800px";

// lebar slot mengikuti kondisi media pertama yang cocok pada sizes
const slot = lebarLayar <= 600 ? 480 : 800;

// kebutuhan piksel adalah lebar slot dikalikan kerapatan perangkat
const kebutuhan = slot * dpr;

// kandidat terkecil yang memenuhi kebutuhan, atau kandidat terbesar
let dipilih = kandidat[kandidat.length - 1];
for (const k of kandidat) {
  if (k >= kebutuhan) {
    dipilih = k;
    break;
  }
}

console.log(`lebar layar: ${lebarLayar} piksel CSS`);
console.log(`slot tampil: ${slot} piksel CSS`);
console.log(`kebutuhan piksel: ${kebutuhan} piksel`);
console.log(`kandidat terpilih: ${dipilih}w`);
text Keluaran
lebar layar: 420 piksel CSS
slot tampil: 480 piksel CSS
kebutuhan piksel: 960 piksel
kandidat terpilih: 1280w

Keluaran memperlihatkan kasus yang wajar, yaitu kandidat 640w tidak cukup besar untuk kebutuhan 960 piksel, sehingga browser memilih 1280w. Tanpa sizes, browser mengasumsikan slot selebar seluruh layar (viewport), sehingga gambarnya cenderung diunduh lebih besar dari yang diperlukan.

Selain deskriptor w, srcset juga menerima deskriptor kerapatan (density descriptor) berakhiran x, misalnya logo.svg 1x, logo-2x.svg 2x. Bentuk ini cocok untuk gambar yang ukuran slotnya tetap, karena browser cukup membandingkannya dengan kerapatan perangkat tanpa membaca sizes.

picture untuk art direction#

Atribut srcset dan sizes hanya mengganti berkas dengan kandungan gambar yang sama, sedangkan art direction menuntut komposisi yang berbeda, misalnya potongan rapat untuk layar sempit dan tampilan lebar untuk layar besar. Elemen picture menyelesaikannya dengan menyediakan beberapa elemen source yang masing-masing membawa kondisi media dan kandidatnya, disusul satu elemen img wajib sebagai isi yang dirender.

html Contoh: picture dengan dua potongan gambar
<picture>
  <source media="(max-width: 600px)" srcset="potongan-kecil.svg">
  <img src="potongan-lebar.svg"
    alt="Papan pengumuman pada dinding, tampilan lebar"
    width="800" height="400">
</picture>
svg potongan-kecil.svg
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400" role="img" aria-labelledby="judul-potongan-kecil">
  <title id="judul-potongan-kecil">Potongan rapat papan pengumuman untuk layar sempit</title>
  <rect width="400" height="400" fill="#f5f5f4"/>
  <rect x="40" y="40" width="320" height="320" rx="10" fill="#d6c39a" stroke="#8d6e63" stroke-width="8"/>
  <rect x="80" y="90" width="240" height="60" rx="6" fill="#ffffff"/>
  <rect x="80" y="180" width="240" height="60" rx="6" fill="#ffffff"/>
  <rect x="80" y="270" width="180" height="60" rx="6" fill="#ffffff"/>
</svg>
svg potongan-lebar.svg
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="400" viewBox="0 0 800 400" role="img" aria-labelledby="judul-potongan-lebar">
  <title id="judul-potongan-lebar">Tampilan lebar papan pengumuman pada dinding untuk layar lebar</title>
  <rect width="800" height="400" fill="#f5f5f4"/>
  <rect y="330" width="800" height="70" fill="#a1887f"/>
  <rect x="280" y="80" width="240" height="180" rx="8" fill="#d6c39a" stroke="#8d6e63" stroke-width="6"/>
  <rect x="300" y="110" width="200" height="34" rx="4" fill="#ffffff"/>
  <rect x="300" y="160" width="200" height="34" rx="4" fill="#ffffff"/>
  <rect x="80" y="120" width="120" height="140" rx="8" fill="#b0bec5"/>
  <rect x="620" y="150" width="120" height="110" rx="8" fill="#b0bec5"/>
</svg>

Browser menggunakan source pertama yang kondisinya cocok, sehingga urutannya harus dari yang paling khusus menuju yang paling umum. Elemen img di bagian akhir bukan opsional, melainkan satu-satunya elemen yang benar-benar dirender, dan sekaligus menjadi cadangan bagi browser yang tidak mengenal picture. Atribut alt, width, dan height milik img itulah yang berlaku, sehingga teks penggantinya perlu mendeskripsikan gambar yang paling mungkin tampil.

html Contoh: picture untuk format modern
<picture>
  <source type="image/avif" srcset="foto.avif">
  <source type="image/webp" srcset="foto.webp">
  <img src="foto.jpg" alt="Ruang baca perpustakaan" width="1280" height="720">
</picture>

Contoh berkas utuh#

Berkas berikut menyatukan dua pola pada satu halaman, yaitu peralihan resolusi dengan srcset dan sizes pada gambar pertama, serta art direction dengan picture pada gambar kedua. Simpan berkas itu bersama suasana-320.svg, suasana-640.svg, suasana-1280.svg, potongan-kecil.svg, dan potongan-lebar.svg dalam satu folder, lalu bukanya di browser dan ubah lebar jendelanya. Gambar pertama berpindah kandidat secara halus, sedangkan gambar kedua berpindah komposisi pada titik 600 piksel.

html responsif.html
<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Galeri gambar responsif</title>
  <style>
    body { font-family: sans-serif; max-width: 52rem; margin: 0 auto; padding: 0 1rem; }
    img { max-width: 100%; height: auto; }
  </style>
</head>
<body>
  <h1>Galeri gambar responsif</h1>

  <h2>Peralihan resolusi dengan srcset</h2>
  <img
    src="suasana-640.svg"
    srcset="suasana-320.svg 320w, suasana-640.svg 640w, suasana-1280.svg 1280w"
    sizes="(max-width: 600px) 480px, 800px"
    alt="Suasana ruang baca dengan meja, buku, dan lampu"
    width="1280" height="720">

  <h2>Pengarahan seni dengan picture</h2>
  <picture>
    <source media="(max-width: 600px)" srcset="potongan-kecil.svg">
    <img src="potongan-lebar.svg"
      alt="Papan pengumuman pada dinding, tampilan lebar"
      width="800" height="400">
  </picture>
</body>
</html>

Kandidat pada contoh ini berupa berkas SVG kecil agar seluruh asetnya dapat diperiksa, sedangkan pada praktiknya kandidat yang sama berlaku untuk berkas JPEG, WebP, atau AVIF dengan lebar yang dinyatakan oleh deskriptornya. Lebar jendela dapat diubah perlahan untuk mengamati perpindahan kandidat, dan alat simulasi perangkat pada DevTools mempercepat pengujian ukuran tertentu. Tab jaringan pada DevTools juga memperlihatkan berkas mana yang benar-benar diunduh pada setiap lebar. Yang berpindah di balik layar hanyalah pilihan berkas, sedangkan markup di halaman tidak pernah berubah.

Kesalahan umum#

Menggunakan deskriptor w tanpa sizes. Browser mengasumsikan gambar menempati seluruh lebar layar dan mengunduh kandidat yang terlalu besar. Lengkapi srcset berdeskriptor w dengan sizes yang menggambarkan slot tampilnya.

Deskriptor w tidak sesuai lebar asli berkas. Perbandingan kebutuhan piksel dengan kandidat menjadi keliru, sehingga gambar buram atau kandidat yang diunduh berlebihan. Catat lebar asli setiap berkas dan tuliskan dengan benar pada deskriptornya.

Menyusun source dalam urutan yang salah. Browser menggunakan kondisi pertama yang cocok, sehingga source yang paling umum yang ditulis lebih dahulu akan selalu menutup kandidat di bawahnya. Susun dari yang paling khusus, dan biarkan img sebagai penutup.

Menyingkirkan elemen img dari picture. Elemen itu bukan cadangan yang boleh hilang, melainkan satu-satunya yang dirender, sehingga picture tanpa img tidak menampilkan apa pun dan tidak sah. Selalu tutup picture dengan satu img lengkap beserta alt-nya.

Menggunakan picture untuk sekadar mengganti resolusi. Bila kandungan gambarnya sama dan hanya ketajamannya yang berbeda, srcset dengan sizes sudah cukup dan markupnya lebih pendek. Simpan picture untuk pergantian komposisi dan pergantian format.

Ringkasan#

  • srcset dengan deskriptor w mendaftar kandidat berdasarkan lebar aslinya, dan sizes menyatakan lebar slot agar browser dapat menghitung kebutuhan pikselnya.
  • Browser memilih kandidat terkecil yang lebar setidaknya sama dengan lebar slot dikalikan kerapatan perangkat, dan mengasumsikan seluruh lebar layar bila sizes tidak ada.
  • Deskriptor x membandingkan kandidat langsung dengan kerapatan perangkat dan tidak memerlukan sizes.
  • Elemen picture mengganti komposisi melalui source berkondisi media serta format melalui source bertipe, dengan img sebagai elemen yang dirender dan sekaligus cadangannya.

Referensi#