{i>Syntax

Dalam modul ini, Anda akan mempelajari cara memberi browser pilihan gambar sehingga browser dapat membuat 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. Sintaks ini memungkinkan browser untuk memecahkan masalah yang sangat sulit, terlepas dari kami: meminta dan merender sumber gambar yang disesuaikan dengan konteks penjelajahan pengguna dengan lancar, termasuk ukuran area pandang, kepadatan tampilan, preferensi pengguna, bandwidth, dan berbagai faktor lainnya.

Ini pertanyaan yang besar—tentunya lebih dari sekadar memikirkan hal ini saat kita hanya memberi markup suatu gambar untuk web, dan melakukannya dengan baik melibatkan lebih banyak hal informasi daripada yang dapat kita akses.

Menjelaskan kepadatan dengan x

<img> dengan lebar tetap akan menempati area pandang yang sama dalam konteks penjelajahan apa pun, terlepas dari kepadatan pengguna tampilan—jumlah {i>pixel<i} fisik yang membentuk layarnya. Misalnya, gambar dengan lebar inheren 400px akan menempati hampir seluruh area pandang browser di Google Pixel asli dan Pixel 6 Pro yang jauh lebih baru—kedua perangkat memiliki 412px yang dinormalkan area pandang lebar piksel logis.

Namun, Pixel 6 Pro memiliki layar yang jauh lebih tajam: 6 Pro memiliki resolusi fisik sebesar 1440 × 3120 piksel, sedangkan Pixel berukuran 1080 × 1920 piksel—yaitu, jumlah piksel hardware yang membentuk layar itu sendiri.

Rasio antara piksel logis perangkat dan piksel fisik adalah rasio piksel perangkat untuk tampilan tersebut (DPR). DPR adalah dihitung dengan membagi resolusi layar perangkat yang sebenarnya dengan piksel CSS area pandang.

DPR 2 ditampilkan di jendela konsol.

Jadi, Pixel yang 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 {i>pixel<i} perangkat sebesar 2—resolusi fisik layar adalah menggandakan resolusi logis. Setiap perangkat sebelum iPhone 4 memiliki DPR 1: satu piksel logis hingga satu piksel fisik.

Jika Anda melihat gambar selebar 400px tersebut di layar dengan DPR 2, setiap piksel logis dirender di empat bagian piksel fisik tampilan: dua horizontal dan dua vertikal. Gambar tidak mendapatkan manfaat dari layar berkepadatan tinggi—gambar akan terlihat sama seperti yang akan ditampilkan pada layar dengan DPR 1. Tentu saja, apa pun yang "digambar" oleh mesin rendering browser—teks, bentuk CSS, atau SVG, misalnya—akan digambar agar sesuai dengan layar dengan kepadatan yang lebih tinggi. Namun, seperti yang Anda pelajari dari Format dan Kompresi Gambar, gambar raster bersifat tetap {i>grid<i} piksel. Meskipun mungkin tidak selalu tampak jelas, gambar raster yang ditingkatkan kualitasnya agar sesuai dengan layar yang memiliki kepadatan 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. Saat diperkecil agar sesuai dengan ruang dalam tata letak dengan lebar 400 piksel logis, sumber gambar 800 piksel tersebut memiliki kepadatan piksel dua kali lipat—pada layar dengan DPR 2, itu akan terlihat bagus dan tajam.

Tampilan jarak dekat kelopak bunga yang menunjukkan perbedaan kepadatan.

Karena layar dengan DPR 1 tidak dapat memanfaatkan kepadatan gambar yang ditingkatkan, skala gambar akan diperkecil agar sesuai dengan — dan seperti yang Anda ketahui, gambar yang diperkecil akan terlihat baik-baik saja. Pada layar berkepadatan rendah, gambar cocok untuk kepadatan lebih tinggi tampilan layar akan terlihat seperti gambar kepadatan rendah lainnya.

Seperti yang Anda pelajari pada Gambar dan Performa, pengguna dengan layar berkepadatan rendah yang melihat sumber gambar diperkecil menjadi 400px hanya memerlukan sumber dengan lebar inheren 400px. Meskipun gambar yang jauh lebih besar akan sesuai untuk semua pengguna secara visual, sumber gambar beresolusi tinggi yang dirender pada layar kecil dan kepadatan rendah akan terlihat seperti gambar kecil lainnya dengan kepadatan rendah, tetapi terasa jauh lebih lambat.

Seperti yang mungkin Anda duga, perangkat seluler dengan DPR 1 sangat jarang, meskipun masih biasa di "desktop" konteks penjelajahan. Menurut data dibagikan oleh Matt Hobbs, sekitar 18% sesi penjelajahan GOV.UK dari November 2022 melaporkan DPR 1. Meskipun gambar berkepadatan tinggi akan terlihat seperti yang diharapkan pengguna, gambar tersebut akan memerlukan bandwidth dan biaya pemrosesan yang jauh lebih tinggi—yaitu kekhawatiran khusus untuk pengguna pada perangkat yang lebih lama dan kurang canggih masih cenderung memiliki layar kepadatan rendah.

Menggunakan srcset memastikan bahwa hanya perangkat dengan tampilan resolusi tinggi yang menerima sumber gambar yang cukup besar untuk terlihat tajam, tanpa meneruskan sumber gambar yang sama biaya {i>bandwidth<i} pada pengguna dengan tampilan resolusi yang 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 di src, dan sintaksis yang mendeskripsikan sumber gambar tersebut. Setiap kandidat di srcset dijelaskan oleh lebar bawaannya ("sintaksis w") atau kepadatan yang diinginkan ("sintaksis x").

Sintaksis x adalah singkatan untuk "sumber ini sesuai untuk tampilan dengan kepadatan ini"—kandidat yang diikuti dengan 2x adalah sesuai untuk tampilan dengan DPR 2.

<img src="low-density.jpg" srcset="double-density.jpg 2x" alt="...">

Browser yang mendukung srcset akan diberi dua kandidat: double-density.jpg, yang dijelaskan 2x sebagai yang sesuai untuk tampilan dengan DPR 2, dan low-density.jpg dalam atribut src—kandidat yang dipilih jika tidak ada yang lebih sesuai ditemukan di srcset. Bagi browser yang tidak mendukung srcset, atribut dan kontennya akan diabaikan—konten src akan diminta, seperti biasa.

Nilai yang ditentukan dalam atribut srcset mudah disalahartikan sebagai petunjuk. 2x tersebut memberi tahu browser bahwa akan sesuai untuk digunakan pada tampilan dengan DPR 2—informasi tentang sumber itu sendiri. Tidak memberi tahu {i>browser<i} bagaimana menggunakan sumber tersebut, hanya memberi tahu {i>browser<i} bagaimana sumber tersebut dapat digunakan. Ini adalah perbedaan yang kecil, tapi penting: ini adalah gambar kepadatan ganda, bukan gambar untuk digunakan pada tampilan kepadatan ganda.

Perbedaan antara sintaksis yang menyatakan "sumber ini sesuai untuk tampilan 2x" dan yang bertuliskan "gunakan sumber ini di layar 2x" sedikit di cetak, tetapi kepadatan tampilan hanyalah salah satu dari sekian banyak faktor yang saling berkaitan yang digunakan browser untuk memutuskan kandidat dirender, hanya beberapa yang bisa Anda ketahui. Misalnya: satu per satu, Anda dapat menentukan apakah pengguna telah mengaktifkan preferensi browser hemat bandwidth melalui kueri media prefers-reduced-data, dan gunakan kueri tersebut untuk selalu mengikutsertakan pengguna ke gambar yang berkepadatan rendah terlepas dari kepadatan tampilan mereka—tetapi jika tidak diterapkan secara konsisten, oleh setiap developer, di setiap situs, hal tersebut tidak akan banyak berguna bagi pengguna. Mereka mungkin mendapatkan preferensi yang dihormati di satu situs, dan menemui dinding gambar yang merusak bandwidth di situs berikutnya.

Algoritma pemilihan resource yang sengaja tidak jelas yang digunakan oleh srcset/sizes memberi ruang bagi browser untuk memutuskan kepadatan yang lebih rendah gambar dengan penurunan bandwidth, atau berdasarkan preferensi untuk meminimalkan penggunaan data, tanpa kami bertanggung jawab atas bagaimana, atau kapan, atau pada ambang batas apa. Tidak ada gunanya mengambil tanggung jawab—dan menambah pekerjaan—sehingga browser lebih siap menanganinya untuk Anda.

Mendeskripsikan lebar dengan w

srcset menerima jenis deskripsi kedua untuk kandidat sumber gambar. Alat ini jauh lebih ampuh—dan untuk tujuan kita, akan jauh lebih mudah dipahami. Daripada 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 identik konten, pemangkasan yang sama, dan rasio aspek yang sama. Namun dalam kasus ini, Anda ingin browser pengguna memilih di antara dua kandidat: {i>small.jpg<i}, sumber dengan lebar inheren 600px, dan large.jpg, sumber dengan lebar inheren 1200px.

srcset="small.jpg 600w, large.jpg 1200w"

Ini tidak memberi tahu browser apa yang harus dilakukan dengan informasi ini—hanya memberinya daftar kandidat untuk menampilkan gambar. Sebelum browser bisa membuat keputusan tentang sumber mana yang akan dirender, Anda perlu memberikannya sedikit informasi tambahan: a deskripsi tentang cara merender gambar di halaman. Untuk melakukannya, gunakan atribut sizes.

Mendeskripsikan penggunaan dengan sizes

Browser memiliki performa yang luar biasa dalam hal mentransfer gambar. Permintaan aset gambar akan dimulai dalam waktu lama sebelum permintaan stylesheet atau JavaScript—sering kali bahkan sebelum markup telah diurai sepenuhnya. Saat browser membuat permintaan ini, tidak memiliki informasi tentang halaman itu sendiri, terlepas dari markup—bahkan mungkin tidak memulai permintaan untuk stylesheet eksternal, apalagi menerapkannya. Pada saat browser mengurai markup Anda dan mulai membuat permintaan, hanya memiliki informasi tingkat browser: ukuran area pandang pengguna, kepadatan piksel layar pengguna, preferensi pengguna, dan sebagainya.

Ini tidak memberi tahu kita apa pun tentang bagaimana gambar dimaksudkan untuk dirender dalam tata letak halaman—bahkan tidak dapat menggunakan area pandang sebagai proxy untuk batas atas ukuran img, karena dapat menempati penampung scroll horizontal. Kita perlu memberikan informasi ini ke browser dan melakukannya dengan menggunakan markup. Hanya itu yang dapat kita gunakan untuk permintaan ini.

Seperti srcset, sizes dimaksudkan untuk membuat informasi tentang gambar tersedia segera setelah markup diuraikan. Sama seperti srcset adalah singkatan dari "ini adalah file sumber dan ukurannya yang melekat," atribut sizes adalah singkatan dari "di sini adalah ukuran gambar yang dirender dalam tata letak". Cara Anda mendeskripsikan gambar relatif terhadap area pandang—sekali lagi, area pandang adalah satu-satunya informasi tata letak yang dimiliki browser saat permintaan gambar dibuat.

Hal ini mungkin terdengar sedikit bertele-tele, tetapi dalam praktiknya jauh lebih mudah untuk dipahami:

<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 dalam tata letak yang ditempati img memiliki lebar 80vw—80% area pandang. Ingat, ini bukan petunjuk, tetapi deskripsi ukuran gambar dalam tata letak halaman. Tidak ada keterangan "buat ini gambar menempati 80% dari area pandang," tetapi "gambar ini akan menempati 80% dari area pandang setelah halaman dirender."

Sebagai pengembang, pekerjaan Anda sudah selesai. Anda telah menjelaskan daftar sumber kandidat dalam srcset dan lebar gambar Anda secara akurat di sizes, dan, seperti halnya sintaksis x di srcset, sisanya bergantung pada browser.

Tetapi untuk memahami sepenuhnya bagaimana informasi ini digunakan, mari kita luangkan waktu sejenak untuk mengambil keputusan yang yang dilakukan browser pengguna saat menemukan markup ini:

Anda telah memberi tahu browser bahwa gambar ini akan menempati 80% dari area pandang yang tersedia—jadi, jika kita merender img ini pada perangkat dengan area pandang selebar 1000 piksel, gambar ini akan menempati 800 piksel. {i>Browser<i} kemudian akan mengambil nilai itu dan membagi terhadap lebar setiap kandidat sumber gambar yang telah kita tentukan di srcset. Sumber terkecil memiliki ukuran inheren 600 {i>pixel<i}, jadi: 600÷800=0,75. Gambar medium kami adalah lebar 1200 piksel: 1200÷800=1,5. Gambar terbesar kami adalah lebar 2000 piksel: 2000÷800=2,5.

Hasil penghitungan tersebut (.75, 1.5, dan 2.5) adalah opsi DPR yang khusus disesuaikan dengan ukuran area tampilan. 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 semua pengguna, sehingga tidak sesuai. Pada perangkat dengan DPR 1, medium.jpg menyediakan kecocokan terdekat—sumber tersebut sesuai untuk ditampilkan pada DPR 1.5, sehingga sedikit lebih besar dari yang diperlukan, tetapi perlu diingat bahwa downscaling proses yang mulus secara visual. Pada perangkat dengan DPR 2, large.jpg adalah kecocokan terdekat sehingga akan dipilih.

Jika gambar yang sama dirender pada area pandang lebar 600 piksel, hasil dari semua perhitungan tersebut akan menjadi sangat berbeda: 80vw sekarang menjadi 480px. Ketika kita membagi sumber lebarnya, kita akan mendapatkan 1.25, 2.5, dan 4.1666666667. Pada ukuran area pandang ini, small.jpg akan dipilih pada 1x perangkat, dan medium.jpg akan cocok di 2x perangkat.

Gambar ini akan terlihat sama di semua konteks penjelajahan ini: semua file sumber kita sama persis terlepas dari dimensinya, dan setiap gambar dirender dengan tajam sesuai kepadatan tampilan pengguna. Namun, bukannya menampilkan large.jpg kepada setiap pengguna untuk mengakomodasi area pandang terbesar dan tampilan dengan kepadatan tertinggi, pengguna akan selalu melihat kandidat terkecil yang sesuai. Dengan menggunakan sintaksis deskriptif, bukan preskriptif, Anda tidak perlu menetapkan titik henti sementara secara manual dan mempertimbangkan area pandang mendatang dan DPR—Anda cukup memberikan informasi ke browser dan mengizinkannya menentukan jawaban untuk Anda.

Karena nilai sizes relatif terhadap area pandang dan sepenuhnya tidak bergantung pada tata letak halaman, nilai ini menambahkan lapisan detail. Jarang ada gambar yang hanya menempati sebagian area tampilan, tanpa margin lebar tetap, padding, atau pengaruh dari elemen lain pada laman. 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 kita dapat padu padankan unit CSS—misalnya, gambar yang memenuhi lebar penuh area tampilan 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 Anda telah menghabiskan banyak waktu bekerja dengan tata letak responsif, Anda mungkin melihat sesuatu yang hilang dari contoh-contoh ini: ruang yang ditempati gambar dalam tata letak sangat mungkin berubah di seluruh titik henti sementara tata letak. Dalam hal ini, Anda perlu untuk meneruskan detail lebih lanjut ke browser: sizes menerima kumpulan kandidat yang dipisahkan koma untuk ukuran objek yang dirender seperti srcset yang menerima kandidat yang dipisahkan koma untuk sumber gambar. Kondisi tersebut menggunakan sintaksis kueri media yang sudah dikenal. Sintaksis ini adalah kecocokan pertama: segera setelah kondisi media cocok, browser berhenti menguraikan atribut sizes, dan nilainya 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—aktif area pandang yang lebih kecil, namun akan menempati lebar penuh area pandang.

  <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 dalam tata letak. Jika Kondisi (min-width: 1200px) tidak cocok, browser akan berpindah ke nilai berikutnya. Karena tidak ada kondisi media 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 yang memenuhi syarat, jadi ini adalah yang dipilih.

Setelah memberikan semua informasi tentang elemen img ini ke browser—sumber potensial, lebar yang melekat, dan bagaimana Anda ingin menampilkan gambar kepada pengguna—browser menggunakan seperangkat aturan kabur untuk menentukan apa yang harus dilakukan dengan informasi tersebut. Jika kedengarannya tidak jelas, mungkin karena memang demikian. Algoritma pemilihan sumber yang dienkode dalam Spesifikasi HTML secara eksplisit samar-samar tentang cara memilih sumber. Setelah sumber, deskripsi mereka, dan bagaimana gambar akan dirender dan semuanya telah diuraikan, browser bebas melakukan apa pun yang diinginkan—Anda tidak dapat mengetahui dengan pasti {i>source<i} yang akan dipilih oleh {i>browser<i}.

Sintaksis yang menyatakan "gunakan sumber ini pada layar resolusi tinggi" dapat diprediksi, tetapi tidak akan membahas masalah intinya dengan gambar dalam tata letak responsif: menghemat bandwidth pengguna. Kepadatan piksel layar hanya terkait secara langsung dengan internet kecepatan koneksi, jika ada. Jika Anda menggunakan laptop berkualitas tinggi, tetapi menjelajahi web melalui koneksi berkuota, di-tethering ke ponsel, atau menggunakan koneksi Wi-Fi pesawat yang goyang—Anda sebaiknya menonaktifkan sumber gambar beresolusi tinggi, kualitas tampilan Anda.

Memberikan keputusan akhir kepada browser memungkinkan peningkatan kinerja yang jauh lebih banyak daripada yang dapat kami kelola dengan preskriptif yang ketat sintaksis. Misalnya: di sebagian besar browser, img yang menggunakan sintaksis srcset atau sizes tidak akan pernah merepotkan saat meminta sumber dengan dimensi dibandingkan dengan yang telah dimiliki pengguna dalam {i>cache<i} browser mereka. Apa gunanya membuat permintaan baru untuk sumber yang akan terlihat identik, ketika {i>browser<i} dapat dengan mulus memperkecil skala sumber gambar yang sudah dimilikinya? Tetapi jika pengguna meningkatkan area tampilan hingga titik di mana gambar baru diperlukan untuk menghindari peningkatan skala, tersebut akan tetap dibuat, sehingga semua terlihat seperti yang Anda harapkan.

Kurangnya kontrol eksplisit itu bisa terasa sedikit menakutkan pada nilai aslinya, tetapi karena Anda menggunakan file sumber dengan besar, kita tidak lagi menimbulkan kerusakan pada pengguna dibandingkan dengan yang kami lakukan pada src sumber tunggal, terlepas dari keputusan yang dibuat oleh browser.

Menggunakan sizes dan srcset

Ada banyak informasi—baik untuk Anda, pembaca, maupun browser. srcset dan sizes adalah sintaksis padat, yang menggambarkan sejumlah informasi yang mengejutkan, dalam jumlah karakter yang relatif sedikit. Yaitu, baik atau buruk, sesuai desain: membuat sintaksis ini lebih ringkas—dan lebih mudah diurai oleh manusia—dapat membuatnya lebih sulit diurai oleh browser. Tujuan semakin banyak kompleksitas yang ditambahkan ke string, semakin besar potensi error parser atau perbedaan perilaku yang tidak disengaja dari satu browser ke browser lain. Namun, ada sisi positifnya: {i>syntax<i} yang lebih mudah dibaca oleh komputer adalah {i>syntax<i} yang lebih mudah ditulis oleh mereka.

srcset adalah contoh yang jelas untuk otomatisasi. Jarang sekali Anda membuat beberapa versi gambar dengan tangan untuk lingkungan production, alih-alih mengotomatiskan proses menggunakan {i>task runner<i} seperti Gulp, pemaket seperti Webpack, CDN seperti Cloudinary, atau fungsi yang sudah tersedia di CMS pilihan Anda. Memberikan informasi yang cukup untuk membuat sumber pertama-tama, sistem akan memiliki cukup informasi untuk menulisnya ke dalam atribut srcset yang valid.

sizes sedikit lebih sulit untuk diotomatiskan. Seperti yang Anda ketahui, satu-satunya cara sistem dapat menghitung ukuran gambar dalam tata letak yang dirender adalah telah merender tata letak. Untungnya, sejumlah alat pengembang telah bermunculan untuk menyederhanakan proses penulisan atribut sizes—dengan efisiensi yang tidak dapat Anda sesuaikan secara manual. respImageLint, misalnya, adalah cuplikan kode yang dimaksudkan untuk memeriksa atribut sizes Anda akurasi dan memberikan saran untuk perbaikan. Project Lazysizes disusupi beberapa kecepatan demi efisiensi dengan menunda permintaan gambar hingga tata letak dibuat, sehingga JavaScript menghasilkan nilai sizes untuk Anda. Jika Anda menggunakan framework rendering sisi klien yang sepenuhnya seperti React atau Vue, ada sejumlah solusi untuk pembuatan dan/atau pembuatan atribut srcset dan sizes, yang akan kita bahas lebih lanjut di CMS dan Framework.