Kueri Kontainer CSS: Kasus Penggunaan Dan Strategi Migrasi

Diterbitkan: 2022-03-10
Ringkasan cepat Kueri penampung CSS membawa kueri media lebih dekat ke elemen target itu sendiri dan memungkinkan mereka untuk beradaptasi dengan hampir semua wadah atau tata letak tertentu. Dalam artikel ini, kita akan membahas dasar-dasar kueri container CSS dan cara menggunakannya saat ini dengan peningkatan progresif atau polyfill.

Saat 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.

Contoh tata letak halaman responsif. Gambar kiri menunjukkan tata letak desktop pada lebar viewport 1280px dan gambar kanan menunjukkan tata letak seluler pada lebar viewport 568px.
Contoh tata letak halaman responsif. Gambar kiri menunjukkan tata letak desktop pada lebar viewport 1280px dan gambar kanan menunjukkan tata letak seluler pada lebar viewport 568px. (Pratinjau besar)

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.

Contoh komponen kartu produk responsif. Gambar kiri menunjukkan komponen pada lebar viewport 720px dan gambar kanan menunjukkan tata letak komponen pada lebar viewport 568px.
Contoh komponen kartu produk responsif. Gambar kiri menunjukkan komponen pada lebar viewport 720px dan gambar kanan menunjukkan tata letak komponen pada lebar viewport 568px. (Pratinjau besar)

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.

Contoh tata letak halaman dengan komponen UI kartu produk yang sama di bagian atas kisi 3 kolom dan daftar bagian bawah.
Contoh tata letak halaman dengan komponen UI kartu produk yang sama di bagian atas kisi 3 kolom dan daftar bagian bawah. (Pratinjau besar)

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 bagaimana kueri media tidak dapat ditautkan secara andal ke dimensi elemen. Berbagai properti CSS dapat memengaruhi dimensi elemen di dalam wadah. Dalam contoh ini, padding kontainer berbeda antara kedua gambar.
Contoh bagaimana kueri media tidak dapat ditautkan secara andal ke dimensi elemen. Berbagai properti CSS dapat memengaruhi dimensi elemen di dalam wadah. Dalam contoh ini, padding kontainer berbeda antara kedua gambar. (Pratinjau besar)

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.

Lihat Pena [Kartu Produk: Berbagai Wadah](https://codepen.io/smashingmag/pen/eYvWVxz) oleh Adrian Bece.

Lihat Kartu Produk Pena: Berbagai Wadah oleh Adrian Bece.

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
Kueri kontainer
(Pratinjau besar)

Jika Anda menggunakan browser yang tidak mendukung kueri penampung, gambar yang menunjukkan contoh kerja yang dimaksud akan disediakan di samping demo CodePen.

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

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.

Dalam contoh ini, kami tidak mengubah ukuran viewport, tetapi elemen penampung <section> itu sendiri yang telah menerapkan properti CSS resize. Komponen secara otomatis beralih di antara tata letak tergantung pada dimensi wadah.
Dalam contoh ini, kita tidak mengubah ukuran viewport, tetapi elemen penampung <section> itu sendiri yang telah menerapkan properti CSS resize. Komponen secara otomatis beralih di antara tata letak tergantung pada dimensi wadah. (Pratinjau besar)

Lihat Pena [Kartu Produk: Kueri Kontainer](https://codepen.io/smashingmag/pen/PopmQLV) oleh Adrian Bece.

Lihat Kartu Produk Pena: Kueri Kontainer oleh Adrian Bece.

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.

Lihat Pena [Kartu Produk: Kueri Kontainer dengan peningkatan progresif](https://codepen.io/smashingmag/pen/zYZwRXZ) oleh Adrian Bece.

Lihat Kartu Produk Pena: Kueri Kontainer dengan peningkatan progresif oleh Adrian Bece.

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