Dipublikasikan: 22 Agustus 2012, Terakhir diperbarui: 14 April 2025
Dengan banyaknya perangkat di pasaran, ada rentang kepadatan piksel layar yang sangat luas yang tersedia. Developer aplikasi perlu mendukung berbagai kepadatan piksel, yang bisa jadi cukup menantang. Di web seluler, tantangan diperparah oleh beberapa faktor:
- Berbagai macam perangkat dengan faktor bentuk yang berbeda.
- Bandwidth jaringan dan masa pakai baterai yang terbatas.
Dalam hal gambar, sasaran developer web adalah menayangkan gambar berkualitas terbaik seefisien mungkin. Di sini, kami membahas beberapa teknik yang berguna untuk melakukannya sekarang dan pada masa mendatang.
Hindari gambar jika memungkinkan
Sebelum mengasumsikan bahwa Anda perlu menyertakan gambar, ingatlah bahwa web memiliki banyak
teknologi canggih yang sebagian besar tidak bergantung pada resolusi dan DPI.
Secara khusus, teks, SVG, dan sebagian besar CSS "hanya berfungsi" karena
fitur penskalaan piksel otomatis di web dengan
devicePixelRatio
.
Meskipun demikian, Anda tidak dapat selalu menghindari gambar raster. Misalnya, Anda mungkin diberi aset yang akan cukup sulit direplikasi dalam SVG atau CSS murni. Anda mungkin sedang menangani foto. Meskipun Anda dapat mengonversi gambar menjadi SVG secara otomatis, memaketkan foto tidak masuk akal karena versi yang diskalakan biasanya tidak terlihat bagus.
Histori kepadatan piksel
Pada awalnya, layar komputer memiliki kepadatan piksel 72 atau 96 titik per inci (DPI).
Kepadatan piksel layar meningkat secara bertahap, sebagian besar didorong oleh kemajuan perangkat seluler, karena pengguna umumnya memegang ponsel lebih dekat ke wajah mereka sehingga piksel lebih terlihat. Pada tahun 2008, ponsel 150 dpi menjadi norma baru. Peningkatan kepadatan layar terus berlanjut, dan ponsel saat ini memiliki layar 300 dpi.
Dalam praktiknya, gambar dengan kepadatan rendah akan terlihat sama di layar baru seperti di layar lama, tetapi dibandingkan dengan gambar yang tajam dengan kepadatan tinggi yang biasa dilihat pengguna, gambar dengan kepadatan rendah terlihat tidak wajar dan berpiksel. Berikut adalah simulasi kasar tampilan gambar 1x di layar 2x. Sebaliknya, gambar 2x terlihat cukup bagus.
1x piksel | Piksel 2x |
![]() |
![]() |
Piksel di web
Saat web didesain, 99% layar memiliki resolusi 96 dpi dan hanya sedikit ketentuan yang dibuat untuk variasi. Setelah memiliki variasi besar dalam ukuran dan kepadatan layar, kita memerlukan cara standar untuk membuat gambar terlihat bagus di semua layar.
Spesifikasi HTML mengatasi masalah ini dengan menentukan piksel referensi yang digunakan produsen untuk menentukan ukuran piksel CSS.
Dengan menggunakan piksel referensi, produsen dapat menentukan ukuran piksel fisik perangkat relatif terhadap piksel standar atau ideal. Rasio ini disebut rasio piksel perangkat.
Menghitung rasio piksel perangkat
Misalkan ponsel memiliki layar dengan ukuran piksel fisik 180 piksel per inci (ppi). Menghitung rasio piksel perangkat memerlukan tiga langkah:
Bandingkan jarak sebenarnya saat perangkat dipegang dengan jarak untuk piksel referensi.
Sesuai spesifikasi, kita tahu bahwa pada ukuran 28 inci, idealnya adalah 96 piksel per inci. Dengan ponsel, kita tahu bahwa wajah orang lebih dekat dengan perangkat mereka daripada dengan laptop dan komputer desktop. Untuk persamaan berikut, kami memperkirakan jarak tersebut adalah 18 inci.
Kalikan rasio jarak dengan kepadatan standar (96 ppi) untuk mendapatkan kepadatan piksel yang ideal untuk jarak yang diberikan.
idealPixelDensity = (28/18) * 96 = 150 piksel per inci (sekitar)
Ambil rasio kepadatan piksel fisik dengan kepadatan piksel ideal untuk mendapatkan rasio piksel perangkat.
devicePixelRatio = 180/150 = 1,2

Jadi, sekarang saat browser perlu mengetahui cara mengubah ukuran gambar agar sesuai dengan layar, sesuai dengan resolusi ideal atau standar, browser akan merujuk ke rasio piksel perangkat 1,2. Artinya, untuk setiap piksel ideal, perangkat ini memiliki 1,2 piksel fisik. Rumus untuk beralih antara piksel ideal (sebagaimana ditentukan oleh spesifikasi web) dan fisik (titik di layar perangkat) adalah sebagai berikut:
physicalPixels = window.devicePixelRatio * idealPixels
Secara historis, vendor perangkat cenderung membulatkan devicePixelRatios
(DPR). iPhone dan iPad Apple melaporkan DPR 1, dan Retina
yang setara melaporkan 2. Spesifikasi CSS merekomendasikan bahwa
unit piksel mengacu pada bilangan bulat piksel perangkat yang paling mendekati piksel referensi.
Salah satu alasan rasio bulat dapat lebih baik adalah karena rasio tersebut dapat menghasilkan artefak sub-piksel yang lebih sedikit.
Namun, kenyataannya lanskap perangkat jauh lebih beragam, dan ponsel Android sering kali memiliki DPR 1,5. Tablet Nexus 7 memiliki DPR ~1,33, yang diperoleh dengan penghitungan yang mirip dengan contoh sebelumnya. Nantikan lebih banyak perangkat dengan DPR variabel pada masa mendatang. Oleh karena itu, Anda tidak boleh berasumsi bahwa klien Anda memiliki DPR bilangan bulat.
Teknik gambar HiDPI
Ada banyak teknik untuk mengatasi masalah menampilkan gambar berkualitas terbaik secepat mungkin, yang secara luas terbagi menjadi dua kategori:
- Mengoptimalkan satu gambar.
- Mengoptimalkan pilihan antara beberapa gambar.
Pendekatan gambar tunggal: gunakan satu gambar, tetapi lakukan sesuatu yang cerdas dengan gambar tersebut. Pendekatan ini memiliki kelemahan bahwa Anda harus mengorbankan performa, karena Anda harus mendownload gambar HiDPI, bahkan di perangkat lama dengan DPI yang lebih rendah. Berikut beberapa pendekatan untuk kasus gambar tunggal:
- Gambar HiDPI yang dikompresi berat
- Format gambar yang sangat keren
- Format gambar progresif
Beberapa pendekatan gambar: menggunakan beberapa gambar, tetapi melakukan sesuatu yang cerdas untuk memilih gambar yang akan dimuat. Pendekatan ini memiliki overhead bawaan bagi developer untuk membuat beberapa versi aset yang sama, lalu mencari strategi keputusan. Berikut ini opsinya:
- JavaScript
- Pengiriman sisi server
- Kueri media CSS
- Fitur browser bawaan (
image-set()
,<img srcset>
)
Gambar HiDPI yang dikompresi berat
Gambar sudah membentuk 60% bandwidth yang dihabiskan untuk mendownload situs rata-rata. Dengan menayangkan gambar HiDPI ke semua klien, kita akan meningkatkan jumlah ini. Seberapa besar ukurannya?
Saya menjalankan beberapa pengujian yang menghasilkan fragmen gambar 1x dan 2x dengan kualitas JPEG pada 90, 50, dan 20.
Dari sampling kecil yang tidak ilmiah ini, tampaknya mengompresi gambar besar memberikan kompromi kualitas terhadap ukuran yang baik. Menurut saya, gambar 2x yang dikompresi berat sebenarnya terlihat lebih baik daripada gambar 1x yang tidak dikompresi.
Meskipun demikian, menayangkan gambar 2x berkualitas rendah yang dikompresi secara ekstrem ke perangkat 2x
lebih buruk daripada menayangkan gambar berkualitas lebih tinggi, dan pendekatan tersebut akan
mengakibatkan penalti kualitas gambar. Jika Anda membandingkan gambar quality: 90
dengan gambar quality: 20
, akan ada penurunan ketajaman gambar
dan peningkatan ketajaman. Artefak dengan quality:20
mungkin tidak dapat diterima
jika gambar berkualitas tinggi penting (misalnya, aplikasi penampil
foto) atau untuk developer aplikasi yang tidak ingin berkompromi.
Perbandingan ini dibuat sepenuhnya dengan JPEG yang dikompresi. Perlu diperhatikan bahwa ada banyak kompromi antara format gambar yang diterapkan secara luas (JPEG, PNG, GIF), yang membawa kita ke…
WebP: Format gambar yang sangat bagus
WebP adalah format gambar yang menarik yang mengompresi dengan sangat baik sekaligus mempertahankan fidelitas gambar yang tinggi.
Salah satu caranya adalah dengan memeriksa dukungan WebP menggunakan JavaScript. Muat gambar 1 piksel
dengan data-uri
, tunggu peristiwa pemuatan atau error diaktifkan, lalu
periksa apakah ukurannya sudah benar. Modernizr dikirimkan dengan
skrip deteksi fitur tersebut, yang tersedia
dengan Modernizr.webp
.
Namun, cara yang lebih baik untuk melakukannya adalah langsung di CSS menggunakan fungsi image(). Jadi, jika Anda memiliki gambar WebP dan penggantian JPEG, Anda dapat menulis hal berikut:
#pic {
background: image("foo.webp", "foo.jpg");
}
Ada beberapa masalah dengan pendekatan ini. Pertama, image()
tidak
diimplementasikan secara luas. Kedua, meskipun kompresi WebP jauh lebih baik daripada JPEG, tetapi masih merupakan peningkatan yang relatif inkremental –
sekitar 30% lebih kecil berdasarkan galeri WebP ini. Dengan demikian, WebP saja
tidak cukup untuk mengatasi masalah DPI tinggi.
Format gambar progresif
Format gambar progresif seperti JPEG 2000, JPEG Progresif, PNG Progresif, dan GIF memiliki manfaat (yang agak diperdebatkan) untuk melihat gambar muncul sebelum dimuat sepenuhnya. Hal ini dapat menimbulkan beberapa overhead ukuran, meskipun ada bukti yang bertentangan tentang hal ini. Jeff Atwood mengklaim bahwa mode progresif "menambahkan sekitar 20% pada ukuran gambar PNG, dan sekitar 10% pada ukuran gambar JPEG dan GIF". Namun, Stoyan Stefanov mengatakan bahwa untuk file berukuran besar, mode progresif lebih efisien (dalam sebagian besar kasus).
Sekilas, gambar progresif terlihat sangat menjanjikan dalam konteks menayangkan gambar berkualitas terbaik secepat mungkin. Idenya adalah browser dapat berhenti mendownload dan mendekode gambar setelah mengetahui bahwa data tambahan tidak akan meningkatkan kualitas gambar (yaitu semua peningkatan fidelitas adalah sub-piksel).
Meskipun koneksi dapat dihentikan dengan cepat, koneksi tersebut sering kali mahal untuk dimulai ulang. Untuk situs dengan banyak gambar, pendekatan yang paling efisien adalah mempertahankan satu koneksi HTTP, menggunakannya kembali selama mungkin. Jika koneksi dihentikan sebelum waktunya karena satu gambar telah didownload cukup banyak, browser harus membuat koneksi baru, yang dapat sangat lambat di lingkungan latensi rendah.
Salah satu solusi untuk hal ini adalah menggunakan permintaan Rentang HTTP, yang memungkinkan browser menentukan rentang byte yang akan diambil. Browser cerdas dapat membuat permintaan HEAD untuk mendapatkan header, memprosesnya, menentukan jumlah gambar yang benar-benar diperlukan, lalu mengambilnya. Sayangnya, Rentang HTTP tidak didukung dengan baik di server web, sehingga pendekatan ini tidak praktis.
Terakhir, batasan yang jelas dari pendekatan ini adalah Anda tidak dapat memilih gambar yang akan dimuat, hanya fidelitas yang bervariasi dari gambar yang sama. Akibatnya, hal ini tidak membahas kasus penggunaan "art direction".
Menggunakan JavaScript untuk menentukan gambar yang akan dimuat
Pendekatan pertama dan paling jelas untuk menentukan gambar yang akan dimuat adalah
menggunakan JavaScript di klien. Pendekatan ini memungkinkan Anda mengetahui
semua hal tentang agen pengguna dan melakukan tindakan yang tepat. Anda dapat
menentukan rasio piksel perangkat dengan window.devicePixelRatio
, mendapatkan lebar
dan tinggi layar, dan bahkan berpotensi melakukan beberapa pemindaian koneksi jaringan
dengan navigator.connection atau mengeluarkan permintaan palsu, seperti yang dilakukan
library foresight.js. Setelah mengumpulkan semua
informasi ini, Anda dapat memutuskan gambar mana yang akan dimuat.
Ada sekitar satu juta library JavaScript yang menggunakan teknik ini. Sayangnya, tidak ada yang sangat luar biasa.
Salah satu kelemahan besar adalah Anda menunda pemuatan gambar hingga setelah parser
look-ahead selesai. Ini pada dasarnya berarti bahwa gambar bahkan tidak akan mulai
didownload hingga setelah peristiwa pageload
diaktifkan. Pelajari lebih lanjut di
artikel Jason Grigsby.
Menentukan gambar yang akan dimuat di server
Anda dapat menunda keputusan ke sisi server dengan menulis pengendali permintaan kustom untuk setiap gambar yang Anda tayangkan. Pengendali tersebut akan memeriksa dukungan Retina berdasarkan User-Agent (satu-satunya informasi yang dibagikan dengan server). Kemudian, berdasarkan apakah logika sisi server ingin menayangkan aset HiDPI, Anda memuat aset yang sesuai (diberi nama sesuai dengan beberapa konvensi yang diketahui).
Sayangnya, User-Agent tidak selalu memberikan informasi
yang cukup untuk memutuskan apakah perangkat harus menerima gambar berkualitas tinggi atau rendah. Selain itu, solusi apa pun yang menggunakan User-Agent
untuk membuat keputusan
gaya harus dihindari.
Menggunakan kueri media CSS
Sebagai deklaratif, kueri media CSS memungkinkan Anda menyatakan niat, dan
memungkinkan browser melakukan hal yang tepat atas nama Anda. Selain penggunaan
kueri media yang paling umum—mencocokkan ukuran perangkat—Anda juga dapat
mencocokkan devicePixelRatio
. Kueri media terkait adalah
rasio-piksel-perangkat, dan memiliki varian min dan maks terkait, seperti yang
Anda harapkan.
Jika Anda ingin memuat gambar DPI tinggi dan rasio piksel perangkat melebihi nilai minimum, berikut yang dapat Anda lakukan:
#my-image { background: (low.png); }
@media only screen and (min-device-pixel-ratio: 1.5) {
#my-image { background: (high.png); }
}
Hal ini menjadi sedikit lebih rumit dengan semua awalan vendor yang dicampurkan, terutama karena perbedaan penempatan yang besar pada awalan "min" dan "max":
@media only screen and (min--moz-device-pixel-ratio: 1.5),
(-o-min-device-pixel-ratio: 3/2),
(-webkit-min-device-pixel-ratio: 1.5),
(min-device-pixel-ratio: 1.5) {
#my-image {
background:url(high.png);
}
}
Dengan pendekatan ini, Anda mendapatkan kembali manfaat penguraian look-ahead, yang hilang dengan solusi JavaScript. Anda juga mendapatkan fleksibilitas dalam memilih titik henti sementara responsif (misalnya, Anda dapat memiliki gambar DPI rendah, sedang, dan tinggi), yang hilang dengan pendekatan sisi server.
Sayangnya, cara ini masih sedikit sulit digunakan, dan menghasilkan CSS yang terlihat
aneh atau memerlukan prapemrosesan. Selain itu, pendekatan ini dibatasi untuk
properti CSS, sehingga tidak ada cara untuk menetapkan <img src>
, dan semua gambar
harus berupa elemen dengan latar belakang. Terakhir, dengan mengandalkan
rasio piksel perangkat secara ketat, Anda dapat mengalami situasi saat ponsel
High-DPI Anda akhirnya mendownload aset gambar 2x besar saat menggunakan
koneksi EDGE. Ini bukan pengalaman pengguna yang terbaik.
Karena image-set()
adalah fungsi CSS, fungsi ini tidak mengatasi masalah untuk tag <img>
. Masukkan @srcset, yang mengatasi masalah ini.
Bagian berikutnya membahas image-set
dan srcset
lebih mendalam.
Fitur browser untuk dukungan DPI tinggi
Pada akhirnya, cara Anda menangani dukungan DPI tinggi bergantung pada persyaratan tertentu. Semua pendekatan yang disebutkan di atas memiliki kekurangan.
Setelah image-set
dan srcset
didukung secara luas, keduanya adalah solusi
terbaik. Ada praktik terbaik tambahan yang dapat mendekatkan kita
untuk browser lama.
Apa perbedaan keduanya? Nah, image-set()
adalah fungsi CSS, yang sesuai untuk digunakan sebagai nilai properti CSS latar belakang.
srcset
adalah atribut khusus untuk elemen <img>
, dengan sintaksis yang serupa.
Kedua tag ini memungkinkan Anda menentukan deklarasi gambar, tetapi atribut srcset
juga memungkinkan Anda mengonfigurasi gambar yang akan dimuat berdasarkan ukuran
tampilan.
Praktik terbaik untuk kumpulan gambar
Sintaksis image-set()
menggunakan satu atau beberapa deklarasi gambar yang dipisahkan koma,
yang terdiri dari string URL atau fungsi url()
, diikuti dengan resolusi
yang sesuai. Contoh:
image-set(
url("image1.jpg") 1x,
url("image2.jpg") 2x
);
/* You can also include image-set without `url()` */
image-set(
"image1.jpg" 1x,
"image2.jpg" 2x
);
Hal ini memberi tahu browser bahwa ada dua gambar yang dapat dipilih. Satu gambar dioptimalkan untuk layar 1x dan yang lainnya untuk layar 2x. Browser kemudian dapat memilih mana yang akan dimuat, berdasarkan berbagai faktor, yang bahkan mungkin mencakup kecepatan jaringan, jika browser cukup cerdas.
Selain memuat gambar yang benar, browser akan menskalakannya sesuai kebutuhan. Dengan kata lain, browser mengasumsikan bahwa 2 gambar dua kali lebih besar dari gambar 1x, sehingga menskalakan gambar 2x ke bawah dengan faktor 2, sehingga gambar tampak berukuran sama di halaman.
Daripada menentukan 1x, 1,5x, atau Nx, Anda juga dapat menentukan kepadatan piksel perangkat tertentu dalam DPI.
Jika khawatir dengan browser lama yang tidak mendukung properti image-set
, Anda dapat menambahkan penggantian untuk memastikan gambar ditampilkan. Contoh:
/* Fallback support. */
background-image: url(icon1x.jpg);
background-image: image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x
);
Kode contoh ini memuat aset yang sesuai di browser yang mendukung set gambar dan kembali ke aset 1x jika tidak.
Pada tahap ini, Anda mungkin bertanya-tanya mengapa tidak langsung melakukan polyfill (yaitu,
mem-build shim JavaScript untuk) image-set()
dan selesai? Ternyata, cukup sulit untuk menerapkan polyfill yang efisien untuk fungsi
CSS. (Untuk penjelasan mendetail alasannya, lihat diskusi gaya www ini).
Srcset gambar
Selain deklarasi yang disediakan image-set
,
elemen srcset
juga mengambil nilai lebar dan tinggi yang sesuai dengan
ukuran area pandang, yang mencoba menayangkan versi yang paling relevan.
<img alt="my awesome image"
src="banner.jpeg"
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 640w, banner-phone-HD.jpeg 640w 2x">
Contoh ini menayangkan banner-phone.jpeg
ke perangkat dengan lebar area pandang di bawah
640 piksel, banner-phone-HD.jpeg
ke perangkat DPI tinggi layar kecil,
banner-HD.jpeg
ke perangkat DPI tinggi dengan layar lebih besar dari 640 piksel, dan
banner.jpeg
ke perangkat lainnya.
Menggunakan image-set untuk elemen gambar
Anda mungkin tergoda untuk mengganti elemen img dengan <div>
dengan latar belakang dan menggunakan pendekatan kumpulan gambar. Hal ini memang berfungsi, dengan
ketentuan. Kelemahannya adalah tag <img>
memiliki nilai semantik
yang lama. Dalam praktiknya, hal ini penting untuk aksesibilitas dan
crawler web.
Anda dapat menggunakan properti CSS konten, yang secara otomatis menskalakan gambar
berdasarkan devicePixelRation
. Contoh:
<div id="my-content-image"
style="content: -webkit-image-set(
url(icon1x.jpg) 1x,
url(icon2x.jpg) 2x);">
</div>
Polyfill srcset
Salah satu fitur praktis srcset
adalah dilengkapi dengan penggantian alami.
Jika atribut srcset tidak diterapkan, semua browser
akan memproses atribut src. Selain itu, karena hanya merupakan atribut HTML, Anda dapat membuat polyfill dengan JavaScript.
Polyfill ini dilengkapi dengan pengujian unit untuk memastikan bahwa polyfill tersebut seserupa mungkin dengan spesifikasi. Selain itu, ada pemeriksaan yang mencegah polyfill mengeksekusi kode apa pun jika srcset diterapkan secara native.
Kesimpulan
Solusi terbaik untuk gambar dengan DPI tinggi adalah memilih SVG dan CSS. Namun, hal ini tidak selalu merupakan solusi yang realistis, terutama untuk situs yang padat gambar.
Pendekatan dalam JavaScript, CSS, dan solusi sisi server memiliki kekuatan
dan kelemahannya masing-masing. Pendekatan yang paling menjanjikan adalah menggunakan image-set
dan srcset
.
Singkatnya, rekomendasi saya adalah sebagai berikut:
- Untuk gambar latar belakang, gunakan image-set dengan fallback yang sesuai untuk browser yang tidak mendukungnya.
- Untuk gambar konten, gunakan polyfill srcset, atau fallback ke menggunakan image-set (lihat di atas).
- Untuk situasi saat Anda bersedia mengorbankan kualitas gambar, pertimbangkan untuk menggunakan gambar 2x yang dikompresi secara ekstensif.