Kueri Kontainer CSS: Kasus Penggunaan Dan Strategi Migrasi
Diterbitkan: 2022-03-10Saat kami menulis kueri media untuk elemen UI, kami selalu menjelaskan bagaimana gaya elemen tersebut bergantung pada dimensi layar. Pendekatan ini bekerja dengan baik ketika responsivitas kueri media elemen target seharusnya hanya bergantung pada ukuran area pandang. Mari kita lihat contoh layout halaman responsive berikut ini.
Namun, Desain Web responsif (RWD) tidak terbatas pada tata letak halaman — komponen UI individual biasanya memiliki kueri media yang dapat mengubah gayanya bergantung pada dimensi area pandang.
Anda mungkin telah melihat masalah dengan pernyataan sebelumnya — tata letak komponen UI individual sering kali tidak bergantung secara eksklusif pada dimensi area pandang. Sementara tata letak halaman adalah elemen yang terkait erat dengan dimensi area pandang dan merupakan salah satu elemen teratas dalam HTML, komponen UI dapat digunakan dalam konteks dan wadah yang berbeda. Jika Anda memikirkannya, area pandang hanyalah sebuah wadah, dan komponen UI dapat disarangkan dalam wadah lain dengan gaya yang memengaruhi dimensi dan tata letak komponen.
Meskipun komponen kartu produk yang sama digunakan di bagian atas dan bawah, gaya komponen tidak hanya bergantung pada dimensi area pandang tetapi juga bergantung pada konteks dan properti CSS penampung (seperti kisi dalam contoh) di mana ia ditempatkan.
Tentu saja, kami dapat menyusun CSS kami sehingga kami mendukung variasi gaya untuk konteks dan wadah yang berbeda untuk mengatasi masalah tata letak secara manual. Dalam skenario terburuk, variasi ini akan ditambahkan dengan penggantian gaya yang akan menyebabkan duplikasi kode dan masalah spesifisitas.
.product-card { /* Default card style */ } .product-card--narrow { /* Style variation for narrow viewport and containers */ } @media screen and (min-width: 569px) { .product-card--wide { /* Style variation for wider viewport and containers */ } }
Namun, ini lebih merupakan solusi untuk keterbatasan kueri media daripada solusi yang tepat. Saat menulis kueri media untuk elemen UI, kami mencoba menemukan nilai viewport "ajaib" untuk breakpoint ketika elemen target memiliki dimensi minimum di mana tata letak tidak rusak. Singkatnya, kami menautkan nilai dimensi area pandang "ajaib" ke nilai dimensi elemen . Nilai ini biasanya berbeda dari dimensi viewport dan rentan terhadap bug saat dimensi container dalam atau tata letak berubah.
Contoh berikut menunjukkan masalah yang tepat ini — meskipun elemen kartu produk responsif telah diterapkan dan terlihat bagus dalam kasus penggunaan standar, namun terlihat rusak jika dipindahkan ke penampung yang berbeda dengan properti CSS yang memengaruhi dimensi elemen. Setiap kasus penggunaan tambahan memerlukan kode CSS tambahan untuk ditambahkan yang dapat menyebabkan kode duplikat, kode mengasapi, dan kode yang sulit untuk dipelihara.
Ini adalah salah satu masalah yang coba diperbaiki oleh kueri penampung. Kueri penampung memperluas fungsionalitas kueri media yang ada dengan kueri yang bergantung pada dimensi elemen target. Ada tiga manfaat utama menggunakan pendekatan ini:
- Gaya kueri penampung diterapkan bergantung pada dimensi elemen target itu sendiri. Komponen UI akan dapat beradaptasi dengan konteks atau wadah apa pun.
- Pengembang tidak perlu mencari nilai dimensi area pandang "angka ajaib" yang menautkan kueri media area pandang ke dimensi target komponen UI dalam wadah tertentu atau konteks tertentu.
- Tidak perlu menambahkan kelas CSS atau kueri media tambahan untuk konteks dan kasus penggunaan yang berbeda.
“Situs web responsif yang ideal adalah sistem komponen modular yang fleksibel yang dapat digunakan kembali untuk melayani dalam berbagai konteks.”
— “Pertanyaan Kontainer: Sekali Lagi Menuju Pelanggaran,” Mat Marquis
Sebelum kita mendalami kueri penampung, kita perlu memeriksa dukungan browser dan melihat bagaimana kita dapat mengaktifkan fitur eksperimental di browser kita.
Dukungan Peramban
Kueri penampung adalah fitur eksperimental, yang saat ini tersedia dalam versi Chrome Canary pada saat artikel ini ditulis. Jika Anda ingin mengikuti dan menjalankan contoh CodePen di artikel ini, Anda harus mengaktifkan kueri penampung di URL pengaturan berikut.
chrome://flags/#enable-container-queries
Jika Anda menggunakan browser yang tidak mendukung kueri penampung, gambar yang menunjukkan contoh kerja yang dimaksud akan disediakan di samping demo CodePen.
Bekerja dengan Kueri Kontainer
Kueri penampung tidak semudah kueri media biasa. Kami harus menambahkan baris kode CSS tambahan ke elemen UI kami untuk membuat kueri penampung berfungsi, tetapi ada alasan untuk itu dan kami akan membahasnya selanjutnya.
Properti Penahanan
CSS contain
properti telah ditambahkan ke sebagian besar browser modern dan memiliki dukungan browser 75% yang layak pada saat menulis artikel ini. Properti contain
terutama digunakan untuk pengoptimalan kinerja dengan memberi petunjuk ke browser bagian mana (subpohon) halaman yang dapat diperlakukan sebagai independen dan tidak akan memengaruhi perubahan pada elemen lain di pohon. Dengan begitu, jika perubahan terjadi pada satu elemen, browser akan merender ulang hanya bagian itu (subpohon) alih-alih seluruh halaman. Dengan nilai properti contain
, kita dapat menentukan jenis penahanan mana yang ingin kita gunakan — layout
, size
, atau paint
.
Ada banyak artikel bagus tentang properti contain
yang menguraikan opsi dan kasus penggunaan yang tersedia secara lebih rinci, jadi saya hanya akan fokus pada properti yang terkait dengan kueri penampung.
Apa hubungan properti kepuasan CSS yang digunakan untuk pengoptimalan dengan kueri penampung? Agar kueri penampung berfungsi, browser perlu mengetahui jika terjadi perubahan pada tata letak turunan elemen yang harus dirender ulang hanya pada komponen tersebut. Browser akan mengetahui untuk menerapkan kode dalam kueri penampung ke komponen yang cocok saat komponen dirender atau dimensi komponen berubah.
Kami akan menggunakan nilai layout
style
untuk contain
, tetapi kami juga memerlukan nilai tambahan yang memberi sinyal kepada browser tentang sumbu tempat perubahan akan terjadi.
-
inline-size
Penahanan pada sumbu inline. Diharapkan nilai ini memiliki kasus penggunaan yang jauh lebih banyak, jadi ini diimplementasikan terlebih dahulu. -
block-size
Penahanan pada sumbu blok. Ini masih dalam pengembangan dan saat ini tidak tersedia.
Satu kelemahan kecil dari properti contain
adalah bahwa elemen tata letak kita harus menjadi anak dari elemen contain
, yang berarti bahwa kita menambahkan tingkat bersarang tambahan.
<section> <article class="card"> <div class="card__wrapper"> <!-- Card content --> </div> </article> </section>
.card { contain: layout inline-size style; } .card__wrapper { display: grid; grid-gap: 1.5em; grid-template-rows: auto auto; /* ... */ }
Perhatikan bagaimana kita tidak menambahkan nilai ini ke section
seperti induk yang lebih jauh dan menjaga wadah sedekat mungkin dengan elemen yang terpengaruh.
“Kinerja adalah seni menghindari pekerjaan dan membuat pekerjaan apa pun yang Anda lakukan seefisien mungkin. Dalam banyak kasus, ini tentang bekerja dengan browser, bukan menentangnya.”
— “Kinerja Rendering,” Paul Lewis
Itulah mengapa kita harus memberi sinyal yang benar kepada browser tentang perubahan tersebut. Membungkus elemen induk yang jauh dengan properti contain
dapat menjadi kontra-produktif dan memengaruhi kinerja halaman secara negatif. Dalam skenario terburuk penyalahgunaan properti contain
, tata letak bahkan dapat rusak dan browser tidak akan merendernya dengan benar.
Permintaan Kontainer
Setelah properti contain
telah ditambahkan ke pembungkus elemen kartu, kita dapat menulis kueri kontainer. Kami telah menambahkan properti contain
ke elemen dengan kelas card
, jadi sekarang kami dapat menyertakan salah satu elemen turunannya dalam kueri wadah.
Sama seperti kueri media biasa, kita perlu mendefinisikan kueri menggunakan properti min-width
atau max-width
dan menyarangkan semua pemilih di dalam blok. Namun, kami akan menggunakan kata kunci @container
alih-alih @media
untuk menentukan kueri container.
@container (min-width: 568px) { .card__wrapper { align-items: center; grid-gap: 1.5em; grid-template-rows: auto; grid-template-columns: 150px auto; } .card__image { min-width: auto; height: auto; } }
card__wrapper
dan card__image
adalah anak-anak dari elemen card
yang memiliki properti contain
yang ditentukan. Saat kami mengganti kueri media biasa dengan kueri wadah, menghapus kelas CSS tambahan untuk wadah sempit, dan menjalankan contoh CodePen di browser yang mendukung kueri wadah, kami mendapatkan hasil berikut.
Harap perhatikan bahwa kueri penampung saat ini tidak muncul di alat pengembang Chrome , yang membuat proses debug kueri penampung agak sulit. Diharapkan dukungan debugging yang tepat akan ditambahkan ke browser di masa mendatang.
Anda dapat melihat bagaimana kueri penampung memungkinkan kami membuat komponen UI yang lebih tangguh dan dapat digunakan kembali yang dapat beradaptasi dengan hampir semua penampung dan tata letak. Namun, dukungan browser yang tepat untuk kueri penampung masih jauh dari fitur tersebut. Mari kita coba dan lihat apakah kita dapat mengimplementasikan kueri penampung menggunakan peningkatan progresif.
Peningkatan Progresif & Polyfill
Mari kita lihat apakah kita dapat menambahkan fallback ke variasi kelas CSS dan kueri media. Kita dapat menggunakan kueri fitur CSS dengan aturan @supports
untuk mendeteksi fitur browser yang tersedia. Namun, kami tidak dapat memeriksa kueri lain, jadi kami perlu menambahkan tanda centang untuk nilai contain: layout inline-size style
. Kita harus berasumsi bahwa browser yang mendukung properti inline-size
juga mendukung kueri penampung.
/* Check if the inline-size value is supported */ @supports (contain: inline-size) { .card { contain: layout inline-size style; } } /* If the inline-size value is not supported, use media query fallback */ @supports not (contain: inline-size) { @media (min-width: 568px) { /* ... */ } } /* Browser ignores @container if it's not supported */ @container (min-width: 568px) { /* Container query styles */ }
Namun, pendekatan ini dapat menyebabkan gaya yang diduplikasi karena gaya yang sama diterapkan baik oleh kueri penampung maupun kueri media. Jika Anda memutuskan untuk menerapkan kueri penampung dengan peningkatan progresif, Anda ingin menggunakan pra-pemroses CSS seperti SASS atau pasca-pemroses seperti PostCSS untuk menghindari duplikasi blok kode dan menggunakan campuran CSS atau pendekatan lain sebagai gantinya.
Karena spesifikasi kueri penampung ini masih dalam tahap percobaan, penting untuk diingat bahwa spesifikasi atau implementasi cenderung berubah di rilis mendatang.
Atau, Anda dapat menggunakan polyfill untuk memberikan fallback yang andal. Ada dua polifill JavaScript yang ingin saya soroti, yang saat ini tampaknya dipelihara secara aktif dan menyediakan fitur kueri penampung yang diperlukan:
-
cqfill
oleh Jonathan Neal
Polyfill JavaScript untuk CSS dan PostCSS -
react-container-query
oleh Chris Garcia
Kait dan komponen khusus untuk React
Bermigrasi Dari Kueri Media Ke Kueri Kontainer
Jika Anda memutuskan untuk menerapkan kueri penampung pada proyek yang sudah ada yang menggunakan kueri media, Anda harus memfaktorkan ulang kode HTML dan CSS. Saya menemukan ini sebagai cara tercepat dan paling mudah untuk menambahkan kueri penampung sambil memberikan cadangan yang andal untuk kueri media. Mari kita lihat contoh kartu sebelumnya.
<section> <div class="card__wrapper card__wrapper--wide"> <!-- Wide card content --> </div> </section> /* ... */ <aside> <div class="card__wrapper"> <!-- Narrow card content --> </div> </aside>
.card__wrapper { display: grid; grid-gap: 1.5em; grid-template-rows: auto auto; /* ... */ } .card__image { /* ... */ } @media screen and (min-width: 568px) { .card__wrapper--wide { align-items: center; grid-gap: 1.5em; grid-template-rows: auto; grid-template-columns: 150px auto; } .card__image { /* ... */ } }
Pertama, bungkus elemen HTML root yang memiliki kueri media yang diterapkan padanya dengan elemen yang memiliki properti contain
.
<section> <article class="card"> <div class="card__wrapper"> <!-- Card content --> </div> </article> </section>
@supports (contain: inline-size) { .card { contain: layout inline-size style; } }
Selanjutnya, bungkus kueri media dalam kueri fitur dan tambahkan kueri penampung.
@supports not (contain: inline-size) { @media (min-width: 568px) { .card__wrapper--wide { /* ... */ } .card__image { /* ... */ } } } @container (min-width: 568px) { .card__wrapper { /* Same code as .card__wrapper--wide in media query */ } .card__image { /* Same code as .card__image in media query */ } }
Meskipun metode ini menghasilkan beberapa kode mengasapi dan kode duplikat, dengan menggunakan SASS atau PostCSS Anda dapat menghindari duplikasi kode pengembangan, sehingga kode sumber CSS tetap dapat dipertahankan.
Setelah kueri penampung menerima dukungan browser yang tepat, Anda mungkin ingin mempertimbangkan untuk menghapus blok kode @supports not (contain: inline-size)
dan terus mendukung kueri penampung secara eksklusif.
Stephanie Eckles baru-baru ini menerbitkan artikel bagus tentang kueri penampung yang mencakup berbagai strategi migrasi. Saya sarankan memeriksanya untuk informasi lebih lanjut tentang topik tersebut.
Skenario Kasus Penggunaan
Seperti yang telah kita lihat dari contoh sebelumnya, kueri penampung paling baik digunakan untuk komponen yang sangat dapat digunakan kembali dengan tata letak yang bergantung pada ruang penampung yang tersedia dan yang dapat digunakan dalam berbagai konteks dan ditambahkan ke penampung yang berbeda di halaman.
Contoh lain termasuk (contoh memerlukan browser yang mendukung kueri penampung):
- Komponen modular seperti kartu, elemen formulir, spanduk, dll.
- Tata letak yang dapat disesuaikan
- Pagination dengan fungsi berbeda untuk seluler dan desktop
- Eksperimen menyenangkan dengan pengubahan ukuran CSS
Kesimpulan
Setelah spesifikasi diterapkan dan didukung secara luas di browser, kueri penampung mungkin menjadi fitur yang mengubah permainan. Ini akan memungkinkan pengembang untuk menulis kueri pada tingkat komponen, memindahkan kueri lebih dekat ke komponen terkait, alih-alih menggunakan kueri media viewport yang jauh dan hampir tidak terkait. Ini akan menghasilkan komponen yang lebih kuat, dapat digunakan kembali, dan dapat dirawat yang dapat beradaptasi dengan berbagai kasus penggunaan, tata letak, dan wadah.
Saat ini, kueri penampung masih dalam tahap awal, eksperimental dan implementasinya cenderung berubah. Jika Anda ingin mulai menggunakan kueri penampung dalam proyek Anda hari ini, Anda harus menambahkannya menggunakan peningkatan progresif dengan deteksi fitur atau menggunakan polifill JavaScript. Kedua kasus akan menghasilkan beberapa overhead dalam kode, jadi jika Anda memutuskan untuk menggunakan kueri penampung di fase awal ini, pastikan untuk merencanakan pemfaktoran ulang kode setelah fitur tersebut didukung secara luas.
Referensi
- “Kueri Kontainer: Panduan Memulai Cepat” oleh David A. Herron
- “Say Hello To CSS Container Query,” Ahmad Shadeed
- “Penahanan CSS Di Chrome 52,” Paul Lewis
- “Membantu Peramban Mengoptimalkan Dengan Properti Berisi CSS,” Rachel Andrew