{i>Syntax

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.

DPR 2 ditampilkan di jendela konsol.

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.

Tampilan close-up kelopak bunga yang menunjukkan perbedaan kepadatan.

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.