Tutorial CSS / Gambar dan Video Responsif dengan aspect-ratio dan object-fit
Media responsif membutuhkan ukuran elemen yang masuk akal sekaligus aturan yang disengaja untuk menyesuaikan kontennya. aspect-ratio membantu menetapkan proporsi kotak, sementara object-fit: cover atau contain menentukan apakah gambar atau video mengisi atau menyesuaikan dalam kotak tersebut.
Pisahkan dimensi intrinsik dan ukuran tampilan
Jika ukuran asli adalah 400×300, rasio adalah 4:3. Jika lebar tampilan adalah 288px dan menjaga proporsi yang sama, tinggi tampilan adalah 216px. Lebar dan tinggi pada HTML memberikan informasi mengenai ukuran dan rasio gambar, dan CSS mengontrol ukuran yang akan ditampilkan di halaman. Alih-alih menyelesaikan masalah dengan menghapus properti ukuran di HTML, periksa nilai apa yang ditimpa di CSS.
img { max-width: 100%; height: auto; }
/* Instead of forcing the small original size to grow, it is reduced to fit the parent. */
max-width: 100% adalah batas atas yang mencegahnya menjadi lebih lebar dari induknya dan tidak otomatis memperbesar gambar kecil hingga memenuhi induknya. width: 100% adalah spesifikasi yang memenuhi lebar induk, sehingga dapat diperbesar melebihi ukuran aslinya. Kejernihan foto dan ukuran unduhan adalah masalah yang terpisah. Anda dapat mengunduh file besar meskipun terlihat kecil dengan CSS, dan ketika Anda menggunakan srcset · sizes, browser memilih gambar dari kandidat yang ada, sehingga Anda harus memeriksa ukuran tampilan di layar dan file yang sebenarnya dipilih.
Gunakan aspect-ratio untuk ukuran otomatis
aspect-ratio: 16 / 9 menggunakan rasio lebar 16 terhadap tinggi 9 untuk menghitung ukuran. Jika lebarnya 288px, tingginya 162px. Setidaknya satu ukuran harus otomatis agar perhitungan proporsional dapat dilakukan, dan jika baik lebar maupun tinggi tetap, ukuran tetap tersebut menjadi prioritas meskipun Anda memasukkan properti ini. Anda juga bisa memeriksa kondisi perhitungan ukuran rasio aspek pada MDN.
.thumbnail { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
Flexbox Alignment, Wrapping, gap, grow, dan shrink dapat menyamakan tinggi gambar dalam satu baris. Untuk menghitung tinggi secara otomatis saat menempatkan gambar dengan rasio asli berbeda berdampingan, periksa juga align-items: flex-start induk atau align-self item. Jika rasio terlihat sama setelah hanya mengubah tinggi menjadi otomatis, aturan perataan induk mungkin penyebabnya.
Dalam praktiknya, box-sizing disatukan sebagai border-box. Ketika menambahkan border atau padding, penting untuk mengukur ukuran dan proporsi kotak. Gambar dalam contoh perbandingan di bawah ini tidak memiliki border atau padding untuk menghindari kebingungan.
Bandingkan penyesuaian ukuran dan pemotongan
| Nilai object-fit | Rasio asli | Area tampilan | Catatan |
|---|---|---|---|
| fill | Tidak harus dipertahankan | Memenuhi seluruh kotak | Isi dapat terdistorsi jika rasionya berbeda. |
| cover | pertahankan | Isi tanpa ruang kosong | Jika rasio berbeda, beberapa bagian akan terpotong. |
| contain | pertahankan | Menampilkan seluruh isi | Jika rasio berbeda, ruang kosong akan tersisa |
Menyesuaikan gambar 4:3 ke dalam kotak 16:9 dengan cover memotong bagian atas dan bawahnya. Posisi tengah membagi potongan di antara keduanya; object-position: center top mempertahankan bagian atas dan memotong lebih banyak di bawah. Periksa konten tepi penting sebelum memilih potongan. Latar belakang CSS menggunakan pilihan penyesuaian terkait tetapi memiliki peran konten dan aksesibilitas yang berbeda dari gambar HTML. Lihat Warna dan Gambar Latar CSS: cover dan contain.
Skema berikut menggambarkan gambar praktik geometris yang sama pada rasio aslinya, dengan cover, dengan contain, dan dengan cover yang rata atas. Bandingkan pita tepi berwarna hijau dan merah serta ruang kosong di sisi. Lingkaran tengah tetap terlihat dalam contoh-contoh ini, sehingga pita tepi membuat pemotongan lebih mudah dikenali. Contoh HTML lengkap di bawah ini memungkinkan Anda mereproduksi perbandingan tersebut.
Jalankan perbandingan empat gambar
Simpan sebagai image-ratio.html dan buka. Gambar asli disertakan sebagai data SVG dalam file tersebut, sehingga tidak diperlukan gambar eksternal. Atribut width dan height pada setiap gambar mempertahankan informasi asli 400×300, sedangkan CSS menentukan ukuran dan rasio tampilannya.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>image-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 65rem); margin-inline: auto; padding: 1rem; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
.sample { width: min(100%, 18rem); margin: 0; }
.sample img { display: block; width: 100%; height: auto; background: #e2e2e2; }
.sample p { margin: .5rem 0 0; } .cover, .contain { aspect-ratio: 16 / 9; }
.cover { object-fit: cover; } .contain { object-fit: contain; }
.top { object-position: center top; }
</style>
</head>
<body>
<main><h1>Compare the size and cropping of the same picture</h1><div class="gallery"><div class="sample"><img class="" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>Original 4:3</p></div>
<div class="sample"><img class="cover" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, center</p></div>
<div class="sample"><img class="contain" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 contain</p></div>
<div class="sample"><img class="cover top" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Top green band, bottom red band and center orange circle"><p>16:9 cover, top</p></div>
</div></main>
</body>
</html>
- Pada layar lebar, pastikan lebar setiap gambar dibatasi hingga 18rem. Dengan font root 16px, lebarnya menjadi 288px, tinggi gambar yang mempertahankan rasio asli menjadi 216px, dan sisa area 16:9 setinggi 162px.
- Ubah hanya tinggi
.sample imgmenjadi 300px. Bahkan jika rasio 16:9 diterapkan, periksa bahwa area tersebut 288×300px karena tinggi yang tetap dan kembalikan ke auto. - Ubah hanya align-items dari
.gallerymenjadi stretch. Pastikan tinggi pembungkus dalam baris yang sama disamakan, tetapi proporsi gambar di dalam pembungkus tetap, dan kembalikan ke flex-start. Dalam contoh ini, item Flex adalah pembungkus contoh, bukan gambar. Dalam konfigurasi di mana gambar ditempatkan langsung sebagai item Flex, tinggi otomatis dapat meningkat, jadi penyelarasan harus diperiksa. - Ubah hanya object-position pada
.topmenjadi center bottom. Kali ini, pastikan pita merah tetap ada dan pita hijau terpotong, lalu kembalikan ke center top.
SVG dalam contoh juga memiliki karakteristik menjaga proporsi bentuk. Jika area tampilan elemen gambar salah dan menciptakan ruang kosong, lingkaran tidak selalu akan terdistorsi. Alih-alih hanya melihat bentuk, periksa lebar dan tinggi elemen img di alat pengembang.
Sesuaikan isi video dengan kotak tampilannya
Dalam latihan di bawah ini, video tanpa suara berukuran 400×300 yang dibuat untuk pelajaran ini ditampilkan dalam area 16:9. Video ini tidak memiliki audio atau informasi subtitle, hanya pergerakan lingkaran oranye, yang digunakan untuk memeriksa ruang atas, bawah, dan samping serta operasi pemutaran. Alamat file video WebM untuk latihan disertakan dalam contoh. Dalam lingkungan tanpa jaringan, unduh file ini dan letakkan di folder yang sama dengan HTML, mengganti alamat sumber dengan nama file.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 34rem); margin-inline: auto; padding: 1rem; }
video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
</style>
</head>
<body>
<main><h1>Video display ratio</h1>
<p id="video-description">This silent sample video shows an orange circle moving on a blue background. Play and pause it to compare aspect ratios.</p>
<video controls preload="metadata" width="400" height="300" aria-describedby="video-description">
<source src="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm" type="video/webm">
<a href="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm">Download the sample video</a>
</video></main>
</body>
</html>
Atribut controls memungkinkan pengguna untuk menggunakan operasi browser seperti putar/jeda, dan preload="metadata" adalah petunjuk yang meminta informasi meta dibaca sebelum pemutaran. Metode unduh yang sebenarnya ditentukan oleh browser Anda. Karena kami tidak menyertakan autoplay, tekan tombol putar untuk mengonfirmasi. Jika Anda hanya mengubah object-fit menjadi cover, Anda dapat melihat perbedaan bahwa area tetap sama dan konten di bagian atas dan bawah terpotong. Setelah konfirmasi, kembalikan ke contain.
object-fit menyesuaikan konten dalam elemen yang diganti seperti gambar dan video. Ini tidak mengatur ukuran konten iframe video tertanam dengan cara yang sama: berikan iframe tersebut sebuah wadah dengan proporsi yang sesuai dan atur ukurannya di dalam wadah tersebut. Berbeda dengan contoh dekoratif tanpa suara ini, video dengan audio yang bermakna membutuhkan alternatif yang sesuai, seperti takarir yang memuat dialog dan suara penting. Lihat MDN: object fit, MDN: video.





