Dalam modul ini, Anda akan mempelajari cara memberikan pilihan gambar ke browser sehingga browser dapat mengambil keputusan terbaik tentang apa yang akan ditampilkan. srcset
bukanlah metode untuk menukar sumber gambar pada titik henti sementara tertentu, dan tidak dimaksudkan untuk menukar satu gambar dengan gambar lainnya. Sintaksis ini memungkinkan
browser menyelesaikan masalah yang sangat sulit, terlepas dari kita: dengan lancar meminta dan merender sumber gambar yang disesuaikan dengan konteks penjelajahan pengguna,
termasuk ukuran area pandang, kepadatan tampilan, preferensi pengguna, bandwidth, dan banyak lagi faktor lainnya.
Ini adalah permintaan besar—tentu saja lebih dari yang ingin kita pertimbangkan saat hanya memberi markup gambar untuk web, dan melakukan dengan baik memerlukan lebih banyak informasi daripada yang dapat kita akses.
Mendeskripsikan kepadatan dengan x
<img>
dengan lebar tetap akan menempati jumlah area pandang yang sama dalam konteks penjelajahan apa pun, terlepas dari kepadatan tampilan
pengguna—jumlah piksel fisik yang membuat layarnya. Misalnya, gambar dengan lebar inheren 400px
akan menempati hampir
seluruh area tampilan browser di Google Pixel asli dan Pixel 6 Pro yang lebih baru—kedua perangkat memiliki area pandang lebar
piksel logis 412px
yang dinormalkan.
Pixel 6 Pro memiliki layar yang lebih tajam, tetapi: 6 Pro memiliki resolusi fisik 1440 × 3120 piksel, sedangkan Pixel-nya adalah 1080 × 1920 piksel—yaitu, jumlah piksel hardware yang membentuk layar itu sendiri.
Rasio antara piksel logis dan piksel fisik perangkat adalah rasio piksel perangkat untuk tampilan (DPR) tersebut. DPR dihitung dengan membagi resolusi layar perangkat yang sebenarnya dengan piksel CSS area pandang.
Jadi, Pixel asli memiliki DPR 2,6, sedangkan Pixel 6 Pro memiliki DPR 3,5.
iPhone 4, perangkat pertama dengan DPR lebih besar dari 1, melaporkan rasio piksel perangkat sebesar 2—resolusi fisik layar dua kali lipat resolusi logis. Perangkat apa pun sebelum iPhone 4 memiliki DPR 1: satu piksel logis ke satu piksel fisik.
Jika Anda melihat gambar selebar 400px
tersebut pada layar dengan DPR 2
, setiap piksel logis dirender di empat
piksel fisik layar: dua horizontal dan dua vertikal. Gambar tidak mendapatkan manfaat dari layar berkepadatan tinggi. Gambar akan terlihat
sama seperti pada layar dengan DPR 1
. Tentu saja, apa pun yang "digambar" oleh mesin rendering browser—misalnya, teks, bentuk CSS, atau SVG—akan digambar agar sesuai dengan tampilan yang memiliki kepadatan lebih tinggi. Namun seperti yang Anda pelajari dari Format dan Kompresi Gambar, gambar raster adalah petak piksel tetap. Meskipun mungkin tidak selalu terlihat jelas, gambar raster yang ditingkatkan agar sesuai dengan layar berkepadatan lebih tinggi akan terlihat
resolusi rendah dibandingkan dengan halaman sekitarnya.
Untuk mencegah peningkatan skala ini, gambar yang dirender harus memiliki lebar intrinsik minimal 800
piksel. Jika diperkecil
agar sesuai dengan ruang dalam tata letak selebar 400 piksel logis, sumber gambar 800 piksel tersebut memiliki kepadatan piksel dua kali lipat—pada layar dengan DPR 2
,
sumber gambar tersebut akan terlihat bagus dan tajam.
Karena layar dengan DPR 1
tidak dapat memanfaatkan kepadatan gambar yang ditingkatkan, layar akan diperkecil agar sesuai dengan
tampilan—dan seperti yang Anda ketahui, gambar yang diperkecil akan terlihat baik-baik saja. Pada layar berkepadatan rendah, gambar yang cocok untuk
tampilan berkepadatan lebih tinggi akan terlihat seperti gambar berkepadatan rendah lainnya.
Seperti yang Anda pelajari di Gambar dan Performa, pengguna dengan tampilan kepadatan rendah yang melihat sumber gambar yang diperkecil menjadi 400px
hanya akan memerlukan sumber dengan lebar inheren 400px
. Meskipun gambar yang jauh lebih besar akan cocok untuk semua pengguna secara visual, sumber gambar
berresolusi tinggi yang dirender pada layar kecil dengan kepadatan rendah akan terlihat seperti gambar kecil dengan kepadatan rendah lainnya, tetapi terasa jauh lebih lambat.
Seperti yang Anda duga, perangkat seluler dengan DPR 1 sangat jarang terjadi, meskipun masih umum dalam konteks penjelajahan "desktop". Menurut data yang dibagikan oleh Matt Hobbs, sekitar 18% sesi penjelajahan GOV.UK dari November 2022 melaporkan DPR sebesar 1. Meskipun gambar berkepadatan tinggi akan terlihat seperti yang diharapkan pengguna tersebut, gambar tersebut akan memiliki bandwidth dan biaya pemrosesan yang jauh lebih tinggi—yang menjadi perhatian khusus bagi pengguna pada perangkat yang lebih lama dan kurang canggih kemungkinan masih memiliki layar dengan kepadatan rendah.
Penggunaan srcset
memastikan bahwa hanya perangkat dengan layar beresolusi tinggi yang menerima sumber gambar yang cukup besar agar terlihat tajam, tanpa meneruskan biaya bandwidth
yang sama kepada pengguna dengan layar beresolusi lebih rendah.
Atribut srcset
mengidentifikasi satu atau beberapa kandidat yang dipisahkan koma untuk merender gambar. Setiap kandidat terdiri dari
dua hal: URL, seperti yang akan Anda gunakan dalam src
, dan sintaksis yang menjelaskan sumber gambar tersebut. Setiap kandidat dalam srcset
dideskripsikan oleh lebar inheren ("sintaksis w
") atau kepadatan ("sintaksis x
").
Sintaksis x
adalah singkatan untuk "sumber ini sesuai untuk tampilan dengan kepadatan ini"—kandidat yang diikuti dengan 2x
cocok untuk
tampilan dengan DPR 2.
<img src="low-density.jpg" srcset="double-density.jpg 2x" alt="...">
Browser yang mendukung srcset
akan ditampilkan dengan dua kandidat: double-density.jpg
, yang dideskripsikan oleh 2x
sebagai sesuai
untuk tampilan dengan DPR 2, dan low-density.jpg
dalam atribut src
—kandidat yang dipilih jika tidak ada yang lebih sesuai
di srcset
. Untuk browser tanpa dukungan srcset
, atribut dan kontennya akan diabaikan—konten src
akan diminta, seperti biasa.
Nilai yang ditentukan dalam atribut srcset
mudah disalahartikan sebagai petunjuk. 2x
tersebut akan memberi tahu browser bahwa
file sumber terkait akan cocok untuk digunakan pada layar dengan DPR 2—informasi tentang sumber itu sendiri. URL tidak memberi tahu
browser cara menggunakan sumber tersebut, tetapi hanya memberi tahu browser
bagaimana sumber dapat digunakan. Perbedaan yang kecil tetapi penting: ini
adalah gambar kepadatan ganda, bukan gambar untuk digunakan pada layar kepadatan ganda.
Perbedaan antara sintaksis yang menyatakan "sumber ini sesuai untuk tampilan 2x
" dan yang menyatakan "gunakan sumber ini di layar 2x
"
sedikit terlihat, tetapi kepadatan tampilan hanyalah salah satu dari banyak faktor yang saling tertaut yang digunakan browser untuk menentukan kandidat
yang akan dirender, hanya sebagian yang dapat Anda ketahui. Misalnya: secara individu, Anda dapat menentukan bahwa pengguna telah mengaktifkan
preferensi browser hemat bandwidth melalui kueri media prefers-reduced-data
, dan menggunakannya untuk selalu mengikutsertakan pengguna ke gambar berkepadatan rendah
terlepas dari kepadatan tampilannya—tetapi kecuali jika diterapkan secara konsisten, oleh setiap developer, di setiap situs, hal ini tidak akan banyak berguna bagi pengguna.
Preferensi ini mungkin akan dihormati di satu situs, dan di situs berikutnya akan terhalangi bandwidth.
Algoritma pemilihan resource yang sengaja tidak jelas yang digunakan oleh srcset
/sizes
memberi ruang bagi browser untuk memutuskan memilih gambar kepadatan
yang lebih rendah dengan penurunan bandwidth, atau berdasarkan preferensi untuk meminimalkan penggunaan data, tanpa kita bertanggung jawab atas bagaimana, atau kapan, atau pada
batas berapa. Tidak ada gunanya mengambil tanggung jawab—dan pekerjaan tambahan—bahwa browser lebih siap menanganinya untuk Anda.
Mendeskripsikan lebar dengan w
srcset
menerima jenis deskripsi kedua untuk kandidat sumber gambar. Fungsi ini jauh lebih kuat—dan untuk tujuan kita, jauh lebih mudah dipahami. Alih-alih menandai kandidat sebagai memiliki dimensi yang sesuai untuk kepadatan tampilan tertentu,
sintaksis w
menjelaskan lebar yang melekat pada setiap sumber kandidat. Sekali lagi, setiap kandidat memiliki penyimpanan yang identik untuk dimensinya—konten yang sama, pemangkasan yang sama, dan rasio aspek yang sama. Namun dalam kasus ini, Anda ingin browser pengguna memilih di antara dua kandidat:
small.jpg, sumber dengan lebar inheren 600 piksel, dan large.jpg, sumber dengan lebar bawaan sebesar 1200 piksel.
srcset="small.jpg 600w, large.jpg 1200w"
Parameter ini tidak memberi tahu browser apa yang harus dilakukan dengan informasi ini—cukup memberikan daftar kandidat untuk menampilkan gambar.
Sebelum browser dapat memutuskan sumber mana yang akan dirender, Anda perlu memberikan sedikit informasi tambahan: deskripsi cara gambar akan dirender pada halaman. Untuk melakukannya, gunakan atribut sizes
.
Mendeskripsikan penggunaan dengan sizes
Browser memiliki performa yang sangat tinggi dalam hal mentransfer gambar. Permintaan aset gambar akan dimulai jauh sebelum permintaan stylesheet atau JavaScript sering kali bahkan sebelum markup diurai sepenuhnya. Saat browser membuat permintaan ini, browser tidak memiliki informasi tentang halaman itu sendiri, selain dari markup—browser bahkan mungkin belum memulai permintaan untuk stylesheet eksternal, apalagi menerapkannya. Pada saat browser mengurai markup dan mulai membuat permintaan eksternal, browser hanya memiliki informasi tingkat browser: ukuran area pandang pengguna, kepadatan piksel tampilan pengguna, preferensi pengguna, dan sebagainya.
Hal ini tidak memberi tahu kita apa pun tentang bagaimana gambar seharusnya dirender di tata letak halaman—dan bahkan tidak dapat menggunakan area tampilan
sebagai proxy untuk batas atas ukuran img
, karena dapat menempati penampung scroll horizontal. Kita perlu memberikan informasi ini
kepada browser dan melakukannya menggunakan markup. Hanya itu yang dapat kita gunakan untuk permintaan ini.
Seperti srcset
, sizes
dimaksudkan untuk menyediakan informasi tentang gambar segera setelah markup diuraikan. Sama seperti atribut srcset
adalah singkatan untuk "ini adalah file sumber dan ukuran inherennya", atribut sizes
adalah singkatan untuk "ini
adalah ukuran gambar yang dirender dalam tata letak". Cara Anda mendeskripsikan gambar relatif terhadap area tampilan. Sekali lagi, ukuran
area tampilan adalah satu-satunya informasi tata letak yang dimiliki browser saat permintaan gambar dibuat.
Hal itu mungkin terdengar sedikit rumit dalam proses cetak, tetapi jauh lebih mudah untuk dipahami dalam praktiknya:
<img
sizes="80vw"
srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
src="fallback.jpg"
alt="...">
Di sini, nilai sizes
ini memberi tahu browser bahwa ruang di tata letak yang ditempati oleh img
memiliki lebar 80vw
—80% dari area pandang. Ingat, ini bukan petunjuk, tapi deskripsi ukuran gambar di tata letak halaman. Tidak ada keterangan "buat gambar
ini menempati 80% area pandang", tetapi "gambar ini akan menempati 80% area pandang setelah halaman dirender".
Sebagai developer, tugas Anda sudah selesai. Anda telah menjelaskan secara akurat daftar sumber kandidat dalam srcset
dan lebar gambar
dalam sizes
, dan, seperti halnya sintaksis x
di srcset
, hal lainnya bergantung pada browser.
Namun, untuk memahami sepenuhnya cara informasi ini digunakan, mari luangkan waktu untuk mempelajari keputusan yang dibuat browser pengguna saat menemukan markup ini:
Anda telah memberi tahu browser bahwa gambar ini akan menempati 80% area tampilan yang tersedia. Jadi, jika kita merender img
ini di
perangkat dengan area pandang selebar 1.000 piksel, gambar ini akan menempati 800 piksel. Browser kemudian akan mengambil nilai tersebut dan membaginya dengan lebar setiap kandidat sumber gambar yang telah kita tentukan di srcset
. Sumber terkecil memiliki ukuran inheren 600 piksel,
jadi: 600÷800=0,75. Gambar sedang memiliki lebar 1200 piksel: 1200÷800=1,5. Gambar terbesar adalah 2000 piksel lebar: 2000÷800=2,5.
Hasil penghitungan tersebut (.75
, 1.5
, dan 2.5
), pada dasarnya, opsi DPR disesuaikan secara khusus dengan ukuran area pandang pengguna. Karena browser juga memiliki informasi tentang kepadatan tampilan pengguna, browser membuat serangkaian keputusan:
Pada ukuran area pandang ini, kandidat small.jpg
akan dihapus terlepas dari kepadatan tampilan pengguna—dengan DPR yang dihitung lebih rendah dari 1
, sumber ini akan memerlukan peningkatan skala untuk pengguna mana pun, sehingga tidak sesuai. Pada perangkat dengan DPR 1
, medium.jpg
memberikan
kecocokan yang paling mirip—sumber tersebut sesuai untuk ditampilkan pada DPR 1.5
, sehingga sedikit lebih besar dari yang diperlukan, tetapi ingat bahwa penurunan skala
adalah proses yang lancar secara visual. Pada perangkat dengan DPR 2,large.jpg
adalah kecocokan terdekat, sehingga dipilih.
Jika gambar yang sama dirender pada area pandang lebar 600 piksel, hasil dari semua perhitungan tersebut akan sangat berbeda: 80vw sekarang menjadi 480px.
Saat membagi lebar sumber dengan itu, kita mendapatkan 1.25
, 2.5
, dan 4.1666666667
. Pada ukuran area pandang ini, small.jpg
akan dipilih
di 1x perangkat, dan medium.jpg
akan cocok di 2x perangkat.
Gambar ini akan terlihat identik di semua konteks penjelajahan ini: semua file sumber kita sama persis terlepas dari dimensinya,
dan masing-masing dirender setajam yang dimungkinkan oleh kepadatan tampilan pengguna. Namun, alih-alih menampilkan large.jpg
kepada setiap pengguna
untuk mengakomodasi area tampilan terbesar dan tampilan kepadatan tertinggi, pengguna akan selalu menerima kandidat terkecil yang sesuai.
Dengan menggunakan sintaksis deskriptif, bukan sintaksis preskriptif, Anda tidak perlu menyetel titik henti sementara secara manual dan mempertimbangkan area pandang dan
DPR mendatang—Anda cukup memberikan informasi ke browser dan mengizinkannya menentukan jawabannya untuk Anda.
Karena nilai sizes
relatif terhadap area tampilan dan sepenuhnya tidak bergantung pada tata letak halaman, nilai ini menambahkan lapisan detail.
Gambar yang hanya menempati sebagian area tampilan, tanpa margin lebar tetap, padding, atau pengaruh
dari elemen lain pada halaman, adalah hal yang jarang terjadi. Anda harus sering menyatakan lebar gambar menggunakan kombinasi satuan; persentase, em
, px
, dan seterusnya.
Untungnya, Anda dapat menggunakan calc()
di sini—browser apa pun dengan dukungan native untuk gambar responsif juga akan mendukung calc()
, sehingga memungkinkan kita memadukan unit CSS—misalnya, gambar yang menempati lebar penuh area pandang pengguna, dikurangi margin 1em
di kedua sisi:
<img
sizes="calc(100vw-2em)"
srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1600w, x-large.jpg 2400w"
src="fallback.jpg"
alt="...">
Mendeskripsikan titik henti sementara
Jika menghabiskan banyak waktu mengerjakan tata letak responsif, mungkin ada sesuatu yang hilang dari contoh ini:
ruang yang ditempati gambar dalam tata letak kemungkinan besar akan berubah di seluruh titik henti sementara tata letak. Dalam hal ini, Anda perlu
meneruskan lebih banyak detail ke browser: sizes
menerima kumpulan kandidat yang dipisahkan koma untuk ukuran gambar
yang dirender, seperti srcset
yang menerima kandidat yang dipisahkan koma untuk sumber gambar. Kondisi tersebut menggunakan sintaksis kueri media yang sudah dikenal.
Sintaksis ini merupakan kecocokan pertama: segera setelah kondisi media cocok, browser berhenti mengurai atribut sizes
, dan nilai yang ditentukan akan diterapkan.
Misalnya, Anda memiliki gambar yang dimaksudkan untuk menempati 80% area tampilan, dikurangi satu em
padding di kedua sisi, pada area pandang di atas 1.200 piksel. Pada
area pandang yang lebih kecil, gambar tersebut menempati lebar penuh area tampilan.
<img
sizes="(min-width: 1200px) calc(80vw - 2em), 100vw"
srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
src="fallback.jpg"
alt="...">
Jika area pandang pengguna lebih besar dari 1.200 piksel, calc(80vw - 2em)
akan menjelaskan lebar gambar di tata letak kita. Jika
kondisi (min-width: 1200px)
tidak cocok, browser akan berpindah ke nilai berikutnya. Karena tidak ada kondisi media
tertentu yang terkait dengan nilai ini, 100vw
digunakan sebagai default. Jika Anda menulis atribut sizes
ini menggunakan
kueri media max-width
:
<img
sizes="(max-width: 1200px) 100vw, calc(80vw - 2em)"
srcset="small.jpg 600w, medium.jpg 1200w, large.jpg 2000w"
src="fallback.jpg"
alt="...">
Dalam bahasa sederhana: "apakah (max-width: 1200px)
cocok? Jika belum, lanjutkan. Nilai berikutnya—calc(80vw - 2em)
—tidak memiliki kondisi kualifikasi,
jadi nilai ini yang dipilih.
Setelah Anda memberikan semua informasi kepada browser terkait elemen img
—sumber potensial, lebar yang melekat,
dan cara Anda ingin menampilkan gambar kepada pengguna—browser menggunakan sekumpulan aturan yang tidak jelas untuk menentukan apa yang harus dilakukan dengan
informasi tersebut. Jika kedengarannya samar-samar, baik, itu karena—karena desain. Algoritma pemilihan sumber yang dienkode dalam
spesifikasi HTML secara eksplisit tidak jelas mengenai cara memilih sumber. Setelah sumber, deskripsi, dan cara gambar dirender telah diurai, browser bebas melakukan apa pun yang diinginkannya. Anda tidak dapat mengetahui secara pasti sumber mana yang akan dipilih browser.
Sintaksis yang menyatakan "gunakan sumber ini pada layar resolusi tinggi" akan mudah diprediksi, tetapi tidak akan mengatasi masalah inti pada gambar dalam tata letak responsif: menghemat bandwidth pengguna. Kepadatan piksel layar hanya terkait secara tangensial dengan kecepatan koneksi internet, jika ada. Jika Anda menggunakan laptop kelas atas, tetapi menjelajahi web dengan koneksi berkuota, yang di-tethering ke ponsel, atau menggunakan koneksi Wi-Fi pesawat yang tidak stabil, sebaiknya Anda menonaktifkan sumber gambar beresolusi tinggi, terlepas dari kualitas layarnya.
Membiarkan keputusan akhir kepada browser memungkinkan peningkatan performa yang jauh lebih banyak daripada yang dapat kami kelola dengan sintaksis yang benar-benar preskriptif. Misalnya: di sebagian besar browser, img
yang menggunakan sintaksis srcset
atau sizes
tidak akan pernah mengganggu saat meminta sumber dengan dimensi
yang lebih kecil dari yang sudah dimiliki pengguna di cache browser mereka. Apa gunanya membuat permintaan baru untuk sumber
yang terlihat identik jika browser dapat dengan mudah menurunkan skala sumber gambar yang sudah dimilikinya? Namun, jika pengguna menskalakan
area pandang hingga gambar baru diperlukan untuk menghindari peningkatan skala, permintaan tersebut akan tetap dibuat sehingga
semuanya terlihat seperti yang Anda harapkan.
Kurangnya kontrol eksplisit ini terdengar agak menakutkan, tetapi karena Anda menggunakan file sumber dengan konten yang identik, kecil kemungkinan kita akan memberi pengguna pengalaman yang "rusak" daripada yang kami lakukan dengan src
sumber tunggal, terlepas dari keputusan yang dibuat oleh browser.
Menggunakan sizes
dan srcset
Ini adalah banyak informasi—baik untuk Anda, pembaca, dan untuk browser. srcset
dan sizes
adalah sintaksis padat,
yang menjelaskan jumlah informasi yang mengejutkan dalam karakter yang relatif sedikit. Yaitu, baik atau buruk, dari desain: membuat sintaksis ini kurang ringkas—dan lebih mudah diurai oleh manusia—dapat membuat sintaks ini lebih sulit untuk diurai oleh browser. Makin
kompleksitas yang ditambahkan ke string, makin besar potensi error parser atau perbedaan perilaku
yang tidak disengaja dari satu browser ke browser lain. Namun, ada kelebihannya di sini: sintaksis yang lebih mudah dibaca oleh mesin adalah sintaksis yang lebih mudah ditulis oleh mesin tersebut.
srcset
adalah kasus yang jelas untuk otomatisasi. Sangat jarang Anda membuat beberapa versi gambar secara manual untuk lingkungan produksi. Namun, Anda mungkin harus mengotomatiskan prosesnya menggunakan runner tugas seperti Gulp, pemaket seperti Webpack, CDN pihak ketiga seperti Cloudinary, atau fungsionalitas yang sudah terintegrasi dalam CMS pilihan Anda. Dengan mempertimbangkan informasi yang cukup untuk menghasilkan sumber kita
sejak awal, sistem akan memiliki informasi yang cukup untuk menulisnya ke dalam atribut srcset
yang layak.
sizes
sedikit lebih sulit untuk diotomatisasi. Seperti yang Anda ketahui, satu-satunya cara sistem dapat menghitung ukuran gambar dalam
tata letak yang dirender adalah dengan merender tata letak. Untungnya, sejumlah alat developer telah muncul untuk memisahkan
proses atribut sizes
penulisan tangan dengan efisiensi yang tidak dapat Anda cocokkan secara manual.
Misalnya, respImageLint adalah cuplikan kode yang dimaksudkan untuk memeriksa akurasi atribut sizes
dan memberikan saran untuk peningkatan. Project Lazysizes menurunkan
beberapa kecepatan efisiensi dengan menunda permintaan gambar hingga tata letak telah ditetapkan, sehingga memungkinkan JavaScript
menghasilkan nilai sizes
untuk Anda. Jika Anda menggunakan framework rendering sisi klien yang sepenuhnya seperti React atau Vue, ada
sejumlah solusi untuk membuat dan/atau membuat atribut srcset
dan sizes
, yang akan kita bahas lebih lanjut di CMS dan Framework.