Tutorial CSS / Container Query CSS untuk Komponen yang Dapat Dipakai Ulang

Query ukuran kontainer memungkinkan sebuah komponen merespons ukuran kontainer leluhur yang memenuhi syarat alih-alih hanya viewport. Deklarasikan kontainer query dengan container-type, lalu gunakan @container untuk mengubah gaya keturunan pada ukuran yang sesuai.

Bandingkan kondisi viewport dan kontainer

Bahkan jika lebar browser 1200px, penempatan yang tepat akan bervariasi tergantung apakah kartu berada di area konten utama 700px atau di area sidebar 300px. Sulit untuk mengekspresikan perbedaan ini hanya menggunakan Media Query CSS dan Breakpoint Berdasarkan Konten, di mana kedua kartu berbagi kondisi viewport yang sama. Saat menggunakan kembali bagian-bagian, Anda dapat mengurangi aturan pengecualian spesifik tata letak dengan mengubah konfigurasi internalnya berdasarkan lebar induk.

Jenis kueri Kriteria penilaian peran yang sesuai
@media Lingkungan seperti lebar viewport Jumlah kolom di seluruh halaman, lokasi sidebar
@container ukuran dari kontainer leluhur yang dipilih, dll. Penempatan gambar dan teks di dalam kartu, jarak antar bagian

Query wadah juga membandingkan lebar dari ekspresi kondisional daripada “atur secara horizontal jika layar horizontal.” Ketika bilah samping tumbuh setidaknya 30rem, kartu di dalamnya juga bisa diatur secara horizontal. Jika Anda selalu menginginkan bilah samping yang sempit, Anda juga harus menentukan lebar maksimum dalam tata letak induk.

Deklarasikan wadah query ukuran

.slot { container: panel / inline-size; }
@container panel (min-width: 30rem) {
  .card { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: 1rem; }
}

container: panel / inline-size memberi nama panel pada kontainer dan menerapkan pembatasan ukuran inline (inline-size containment). Dalam penulisan horizontal, dimensi inline adalah horizontal; penulisan vertikal mengubah kesesuaian tersebut. Berikan lebar kontainer melalui tata letak blok luarnya atau track Grid sehingga kartu memiliki ukuran yang bermakna untuk dikueri. Lihat Dasar CSS Grid: Track, Garis, dan Penempatan Item.

Induk untuk mengevaluasi kondisi adalah .slot dan keturunan yang akan menerima gaya kondisional adalah .card. Jangan menulis dalam struktur yang mengubah kartu itu sendiri dengan melihat ukuran kartu itu sendiri. Untuk menghindari masalah kondisi yang berbalik terus-menerus saat ukuran berubah, kueri ukuran beroperasi relatif terhadap leluhur yang sesuai.

inline-size containment membuat ukuran inline kontainer menjadi independen dari kontribusi konten keturunan. Sebuah kontainer shrink-to-fit dapat menjadi sangat kecil secara tidak terduga. Di sini, sebuah block atau Grid track menentukan lebarnya. Menggunakan size containment juga memengaruhi sumbu lain dan dapat meruntuhkan tinggi sesuai konten, jadi pilih containment dengan hati-hati. Untuk informasi lebih lanjut, lihat Anda dapat melihat sejauh mana isolasi ukuran dalam deskripsi container-type di MDN.

Gunakan kembali kartu di lebar induk yang berbeda

Simpan sebagai container-card.html dan buka di browser Anda. Kotak warna adalah elemen contoh yang mewakili area gambar, jadi tidak ada file gambar terpisah. Pada layar yang lebih besar, pisahkan teks utama dan bilah samping hingga 20rem, dan pada 44rem atau kurang, tempatkan kedua area dalam satu kolom.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>container-card.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; }
.layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); gap: 1rem; width: min(100%, 75rem); margin-inline: auto; padding: 1rem; }
.slot { min-width: 0; container: panel / inline-size; }
.card { min-width: 0; padding: 1rem; background: #e8f3fa; overflow-wrap: anywhere; }
.media { min-height: 7rem; background: #287699; }
.card h2 { font-size: 1.25rem; } .card p { margin-bottom: 0; }
@container panel (min-width: 30rem) {
  .card { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: 1rem; align-items: start; }
}
@media (max-width: 44rem) { .layout { grid-template-columns: minmax(0, 1fr); } }
</style>
</head>
<body>
<div class="layout">
<main class="slot"><article class="card"><div class="media" aria-hidden="true"></div><div><h2>Card in the main content area</h2><p>The image and text appear side by side when the parent is at least 30rem wide.</p></div></article></main>
<aside class="slot"><article class="card"><div class="media" aria-hidden="true"></div><div><h2>The same card in a sidebar</h2><p>The sidebar in this example stays at or below 20rem even on a wide screen, so the card keeps its vertical layout.</p></div></article></aside>
</div>
</body>
</html>

Dalam lingkungan default di mana ukuran font awal adalah 16px, 30rem adalah 480px. Jika kontainer konten utama pada layar besar berukuran 480px atau lebih, bagian dalam kartu akan terdiri dari dua kolom, dan pada bilah samping yang ukurannya hingga 320px, bagian dalam kartu akan diatur secara vertikal. Pada layar sempit, saat bilah samping pindah ke bawah, induknya mungkin menjadi lebih lebar. Oleh karena itu, adalah normal bagi kedua kartu ditempatkan secara horizontal pada layar 600px selama lebar induknya memenuhi kondisi.

Kondisi luar 44rem dan kondisi dalam 30rem menyelesaikan masalah yang berbeda. Kondisi pertama menentukan bagaimana menempatkan area pada seluruh halaman, dan kondisi kedua menentukan bagaimana menempatkan gambar dan teks di dalam ruang yang diberikan untuk setiap kartu. Walaupun beberapa leluhur memiliki nama panel, setiap kartu terlebih dahulu memilih kontainer leluhur terdekat yang bernama panel dan mendukung kueri ukuran. Kondisinya lalu dievaluasi pada kontainer itu. Jika kondisi salah, browser tidak mencari kontainer yang lebih jauh hanya untuk membuatnya benar.

Pilih kontainer terdekat dan bernama

Kueri ukuran tanpa nama memilih kontainer leluhur terdekat yang mendukung dimensi ukuran yang ditanyakan, lalu mengevaluasi kondisinya. Bahkan jika area luar lebar, hasilnya bisa berbeda jika kontainer yang lebih sempit ditambahkan di tengah. Anda dapat melihat perbedaan ini secara terpisah dengan menyimpan contoh berikut sebagai container-nested.html.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>container-nested.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%, 42rem); padding: 1rem; }
.outer { width: 100%; container: outer / inline-size; border: 2px solid #789; padding: 1rem; }
.inner { width: min(100%, 17rem); container-type: inline-size; }
.card { padding: 1rem; background: #e8f3fa; overflow-wrap: anywhere; }
.media { min-height: 5rem; background: #287699; }
@container (min-width: 30rem) {
  .card { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 1rem; }
}
</style>
</head>
<body>
<main><h1>Which parent's width is queried?</h1><div class="outer"><div class="inner"><article class="card"><div class="media" aria-hidden="true"></div><p>The nearest inner container has a maximum of 17rem.</p></article></div></div></main>
</body>
</html>

Pada layar lebar, kontainer luar setidaknya 30rem, tetapi kontainer dalam maksimal 17rem. Kondisi tanpa nama memilih elemen dalam terdekat, sehingga kartu ditata secara vertikal. Pertahankan kode lainnya dan ganti @container (min-width: 30rem) dengan yang berikut:

@container outer (min-width: 30rem) {
  .card { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 1rem; }
}

Sekarang kita memilih leluhur luar yang bernama outer, sehingga kartu ditata secara horizontal pada layar lebar. Kartu itu sendiri masih berada dalam batas maksimum 17rem, jadi Anda perlu memeriksa secara terpisah apakah lebar teks di dalam kartu cukup. Nama bukanlah properti yang secara otomatis memperbaiki standar yang salah, tetapi sebuah fungsi yang menentukan leluhur mana yang digunakan sebagai standar. Setelah membandingkan, kembalikan ke kondisi tanpa nama.

Diagnosa kueri yang tidak berlaku

  1. Periksa apakah target dari selektor bersyarat adalah keturunan dari kontainer. Periksa bahwa Anda tidak mencoba menerapkan gaya yang sama pada induknya sendiri.
  2. Periksa nilai container-type pada leluhur dan lebar konten aktual di alat pengembang. Tidak ada kebingungan antara lebar luar, termasuk padding dan border, dan ukuran yang akan dicari.
  3. Periksa apakah kontainer baru telah dibuat, dan jika perlu, tentukan kriteria dengan container-name.
  4. Pada contoh pertama, ganti deklarasi container: panel / inline-size pada .slot dengan container: panel / normal. Slot itu tidak lagi menjadi kontainer kueri ukuran sehingga gaya dasar kartu digunakan. Setelah dikonfirmasi, kembalikan ke inline-size.

Pertahankan kartu vertikal yang dapat dibaca sebagai garis dasar, kemudian tambahkan penempatan horizontal ketika kueri kontainer diterapkan. Garis dasar juga melayani browser yang tidak mendukung kueri ukuran. Periksa dukungan dan perilaku di browser yang benar-benar dibutuhkan pembaca Anda. Lihat MDN: Kueri ukuran dan gaya kontainer.