- 1 Dasar-Dasar
- 2 Flexbox
- 3 Petak dan subpetak
- 4 Kueri penampung
- 5 Overlay native, pemosisian anchor, dan konteks tumpukan
- 6 Pelacakan overflow dan stabilitas tata letak
- 7 Mekanika area pandang dan distribusi trek
- 8 Lajur petak (alias masonry)
1 Dasar-Dasar
Andalkan mesin tata letak browser jika memungkinkan untuk mendapatkan performa yang lebih baik. Gunakan ukuran intrinsik, properti logis, dan aspect-ratio sebelum menggunakan dimensi hardcode atau kueri media yang rumit.
1.1 Mode tata letak mana yang akan digunakan?
Ikuti pohon keputusan dari atas ke bawah dan berhenti pada kecocokan pertama. Perhatikan bahwa tata letak dapat disusun bertingkat satu sama lain dan setiap keputusan didasarkan pada kasus penggunaan untuk penampung tersebut.
- Apakah itemnya berupa baris ATAU kolom sederhana? Gunakan flexbox — 1D, mengutamakan konten, konten didistribusikan di sepanjang satu sumbu.
- Apakah elemen bertingkat perlu sejajar dengan jalur petak induknya? Gunakan subgrid — 2D, mengutamakan hubungan, mewarisi jalur induk sehingga turunan dapat sejajar di seluruh turunan.
- Apakah halaman atau struktur komponennya kompleks dengan baris DAN kolom? Gunakan petak — 2D, mengutamakan tata letak, Anda menentukan kerangka dan konten akan mengisinya.
- Apakah kontennya berupa prosa panjang yang harus dibagi menjadi kolom-kolom yang seimbang? Gunakan multi-kolom — alur 1D, gaya surat kabar.
- Apakah item memiliki tinggi yang bervariasi dan perlu dikemas rapat? Gunakan grid dengan
grid-auto-flow: densesekarang; gunakan masonry native (alias "jalur petak") hanya jika dikirimkan di target Dasar pengukuran Anda (lihat §8). - Apakah elemen perlu mengambang di atas halaman dan tetap tertambat secara spasial ke pemicu, bahkan di seluruh batas DOM atau konteks tumpukan? Gunakan pemosisian anchor —
anchor-namepada pemicu,position-anchorpada overlay (lihat §5).
1.2 Prinsip kerja
- Gunakan properti logis (
inline-size,block-size,margin-inline,padding-block,inset-inline-start) untuk dimensi dan spasi tata letak — lihat CSS: Arsitektur Modern untuk cakupan lengkap. - Terapkan model mental konten-first vs tata letak-first: flexbox saat item menentukan alur, petak saat Anda menentukan kerangka terlebih dahulu.
- Gunakan singkatan
place-*(place-content,place-items,place-self) untuk meratakan di kedua sumbu dalam satu deklarasi. - Gunakan ukuran intrinsik (
min-content,max-content,fit-content()) dan jalur fleksibel (fr,minmax()) sebelumwidth/heighttetap — lebih sedikit kueri media, tata letak yang lebih tangguh. - JANGAN gunakan
overflow: hiddenuntuk menyamarkan masalah tata letak — perbaiki masalah tersebut di sumbernya. Misalnya, elemen tertentu yang diganti seperti<canvas>,<img>,<svg>,<video>,<iframe>menggunakandisplay: inlinesecara default, yang dapat menambahkan celah dalam tata letak tertentu. Daripada memotong celah denganoverflow, hapus celah tersebut dengan menerapkan nilai display-outside blok (misalnya,display: block,grid,flex, dll.). - Gunakan
aspect-ratiountuk mencadangkan ruang bagi media dan mencegah pergeseran tata letak sebelum aset dimuat.
.sidebar { inline-size: max-content; } /* Size to longest unbreakable token. */
.main-content { inline-size: fit-content; } /* Grow to available space, no further. */
.media { aspect-ratio: 16 / 9; inline-size: 100%; block-size: auto; }
body.centered { display: grid; place-content: center; min-block-size: 100dvb; }
Untuk
calc-size()dan ukuran intrinsik yang mempertimbangkan batasan, lihat Menghitung Dengan Ukuran Intrinsik.
2 Flexbox
Tata letak satu dimensi — item mengalir di sepanjang satu sumbu utama dengan perataan pada sumbu silang. Gunakan untuk navbar, toolbar, baris item, dan distribusi baris atau kolom tunggal apa pun.
Lakukan:
- Buat konteks dengan
display: flexdan tetapkan sumbu utama denganflex-direction(rowdefault). - Gunakan
flex-wrap: wrapsetiap kali ada kemungkinan overflow —nowraptanpaoverflow: auto/hiddenakan tumpah pada area pandang yang sempit. - Lapisi
flex-wrap: balancesetelahflex-wrap: wrappada baris item ringkas yang digabungkan (seperti tag cloud, pil filter, grup tombol, atau link navigasi) untuk mendistribusikan item secara merata di seluruh baris dan mencegah item tunggal yang tidak terhubung di baris akhir; browser yang tidak mendukung akan kembali kewrap. - Gunakan singkatan
flex<grow> <shrink> <basis>(misalnya,flex: 1 1 250px) pada item, bukan menetapkanflex-grow/flex-shrink/flex-basissatu per satu. - Gunakan
gap(atau bentuk panjangrow-gap/column-gap) untuk spasi di antara item, bukan margin turunan. - Tambahkan awalan perataan posisi dengan
safe(misalnya,align-items: safe center) agar konten yang dapat difokuskan tidak terpotong saat penampung lebih sempit daripada kontennya. - Dorong satu item ke ujung sumbu utama dengan
margin-inline-start: auto(ataumargin-block-start: auto) — ini adalah escape hatch standar. - Mengganti perataan sumbu silang per item dengan
align-self. - Gunakan
align-itemsuntuk memusatkan semua item pada sumbu silang; gunakanmargin: autopada satu item untuk memusatkannya pada kedua sumbu secara independen; gunakanalign-contenthanya jika penampung digabungkan dan memiliki ruang ekstra di seluruh baris. - Tetapkan
min-inline-size: 0(ataumin-width: 0) pada item flex yang berisi konten panjang yang tidak dapat dipisahkan (URL, kode, string panjang) — item flex tidak akan menyusut di bawah ukuran kontennya secara default, sehingga menyebabkan overflow.
Jangan:
- Jangan gunakan
justify-selfpada item flex — properti ini hanya berfungsi pada tata letak petak, blok, dan yang diposisikan secara absolut. Gunakan margin otomatis. - Jangan gunakan
orderatauflex-direction: *-reverseuntuk mengurutkan ulang konten interaktif. Properti ini hanya mengubah urutan visual; urutan DOM masih mendorong fokus berurutan, sehingga alur tab keyboard tidak akan cocok dengan yang dilihat pengguna. - Jangan bingung antara
space-around(setengah celah di ujung) denganspace-evenly(celah yang sama sebelum, di antara, dan setelah). - Jangan lupa pembalikan sumbu: saat
flex-direction: column,justify-contentsejajar pada sumbu blok danalign-itemssejajar pada sumbu inline — kebalikan dari default. - Jangan mengubah ukuran penampung dan turunannya untuk saling mengisi — ini adalah sumber umum terjadinya overflow dan hasil yang mengejutkan. Berikan ukuran yang pasti pada satu sisi.
- Jangan tetapkan
flex-basisdanwidth/inline-sizepada item yang sama —flex-basislebih diprioritaskan dalam konteks flex danwidthakan diabaikan. Gunakanflex-basis(atau singkatanflex) sebagai satu sumber tepercaya untuk menentukan ukuran item flex.
.card-grid { display: flex; flex-flow: row wrap; gap: 1rem; }
.card-item { flex: 1 1 250px; } /* grow, shrink, basis */
.card-item-action { margin-inline-start: auto; } /* Push to main-axis end. */
.toolbar { display: flex; align-items: safe center; }
.tag-list { display: flex; flex-wrap: wrap; flex-wrap: balance; gap: 0.5rem; }
3 Petak dan subpetak
Tata letak dua dimensi — tentukan baris DAN kolom secara eksplisit, atau biarkan mesin menurunkannya. Subpetak memungkinkan petak bertingkat mewarisi jalur induknya sehingga turunan kedua sejajar dengan elemen seinduk.
Memilih fitur petak:
- Apakah Anda tahu persis berapa banyak kolom yang Anda butuhkan?
- Ya — gunakan jalur eksplisit (
grid-template-columns: 200px 1fr,repeat(3, 1fr), dll.) - Apakah kolom yang berbeda memerlukan ukuran yang berbeda (sidebar + utama, header yang mencakup semuanya)? → gunakan
grid-template-areasuntuk region yang diberi nama dan dapat dibaca - Apakah semua kolom seragam atau diposisikan murni berdasarkan nomor baris? → gunakan
repeat(N, ...)atau garis bernama - Tidak (responsif, jumlah item tidak diketahui) — gunakan
repeat(auto-fit, minmax(min, 1fr)) - Haruskah item di baris terakhir direntangkan untuk mengisi ruang yang tersisa? →
auto-fit - Haruskah trek baris terakhir yang kosong mempertahankan ukuran minimumnya (mempertahankan slot hantu kolom)? →
auto-fill
- Ya — gunakan jalur eksplisit (
- Apakah Anda perlu menempatkan item di lokasi tertentu?
- Ya — gunakan
grid-column: <start> / <end>ataugrid-area: <name> - Tidak (hanya mencakup beberapa jalur, posisi alur tidak penting) — gunakan
grid-column: span <n>
- Ya — gunakan
- Apakah elemen turunan perlu mewarisi ukuran jalur petak induk (perataan tepi tidak rata di seluruh elemen seinduk)?
- Ya — gunakan subgrid pada sumbu yang terpengaruh
- Apakah jumlah anak per sel bervariasi? → subgrid hanya satu sumbu; gunakan
grid-auto-rows/grid-auto-columnsuntuk sumbu lainnya - Apakah jumlah anak sudah diperbaiki? → subgrid pada kedua sumbu tidak masalah
- Tidak — petak standar, tidak memerlukan subpetak
Lakukan:
- Buat konteks dengan
display: grid. - Gunakan
grid-template-areasuntuk tata letak tingkat halaman yang kompleks — nama area mendokumentasikan dirinya sendiri dan deklarasi dapat disejajarkan dalam baris dan kolom agar mudah dibaca secara sekilas. - Gunakan
repeat(auto-fit, minmax(200px, 1fr))untuk petak kartu responsif yang merentangkan trek yang terisi untuk mengisi baris, atauauto-filluntuk mempertahankan trek berulang yang kosong pada ukuran minimumnya. - Gunakan
fruntuk distribusi jalur proporsional danminmax(min, max)untuk jalur yang fleksibel, tetapi terbatas. - Posisikan item dengan
grid-column: span <n>untuk menentukan ukuran di seluruh trek,grid-column: <start> / <end>untuk menempatkan di baris tertentu, ataugrid-area: <name>untuk region bernama. - Gunakan subgrid (
grid-template-columns: subgridataugrid-template-rows: subgrid) untuk mengatasi masalah "tepi tidak rata" dalam daftar kartu — elemen internal seperti judul, metadata, dan CTA sejajar di seluruh elemen seinduk. - Pasangkan deklarasi subpetak dengan deklarasi
grid-template-rows/-columnseksplisit sebelumnya sebagai penggantian cascade yang sama untuk browser lama.
Jangan:
- Jangan mengharapkan ukuran jalur
auto-fit/auto-fillberasal dari konten item — ukuran tersebut berasal dari argumen ukuranrepeat(). - Jangan gunakan
grid-auto-flow: densepada konten interaktif. Properti ini mengemas item secara efisien, tetapi menyusun ulang item secara visual, sehingga mengganggu alur tab keyboard urutan DOM. - Jangan terapkan subgrid ke kedua sumbu jika jumlah turunan bervariasi. Ekstra ditempatkan di jalur terakhir; gunakan
grid-auto-rows/grid-auto-columnsuntuk sumbu implisit. - Jangan bingung antara
justify-items/align-items(menyejajarkan konten item dalam jalurnya) denganjustify-content/align-content(menyejajarkan jalur petak dalam penampung). Menggunakan yang salah tidak akan berpengaruh apa pun. - Jangan gunakan
repeat(auto-fit/auto-fill, ...)tanpainline-sizeyang pasti pada penampung — di dalamdisplay: inline-gridatau item flex tanpa ukuran, penampung tidak memiliki lebar untuk dibagi, sehingga jumlah jalur tidak dapat diprediksi.
3.1 Contoh kode: petak dan subpetak
Shell halaman: <main class="page-layout"> berisi <header>, <aside>, <section class="card-grid"> dengan <div class="card"> turunan, dan <footer>.
/* Align grid-template-areas in rows and columns for readability. */
.page-layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
gap: 1.5rem;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
footer { grid-area: footer; }
.card-grid {
grid-area: main;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-template-rows: auto 1fr; /* title block, body block */
gap: 1rem;
}
.card {
grid-row: span 2;
display: grid;
/* Same-cascade fallback: ignored when subgrid is supported. */
grid-template-rows: auto 1fr;
grid-template-rows: subgrid;
}
4 Kueri container
Membuat kueri ukuran (atau gaya yang dihitung) penampung ancestor, bukan area pandang. Model mental: kueri penampung = konteks komponen; kueri media = tata letak halaman global dan preferensi pengguna (prefers-color-scheme, prefers-reduced-motion).
Lakukan:
- Buat konteks penampungan dengan
container-type: inline-size(kueri khusus lebar) ataucontainer-type: size(kedua sumbu) pada wrapper sebelum turunannya dapat dikueri. - Beri nama penampung dengan
container-name(atau singkatancontainer:container: card / inline-size) jika konteks bertingkat dapat bertabrakan. - Sertakan unit kueri penampung dalam menghitung jenis dan spasi fluid:
cqi/cqb(inline/blok logis),cqw/cqh(fisik),cqmin/cqmax. - Berikan
block-sizeyang pasti pada penampung setiap kalicontainer-type: sizedigunakan — tanpa itu, turunan akan diciutkan karena pembatasan ukuran memaksa penampung mengabaikan kontennya.
Jangan:
- Jangan gunakan
block-sizesebagai nilaicontainer-type— nilai ini tidak valid. Gunakansizeuntuk kedua sumbu. - Jangan berharap ukuran intrinsik turunan akan memengaruhi penampung setelah mendeklarasikan
container-type. Penampung dihitung seolah-olah tidak memiliki turunan setelah penampungan aktif. - Jangan mengandalkan unit kueri penampung di dalam turunan ancestor yang tidak memenuhi syarat; unit tersebut akan kembali ke area pandang kecil (
svw/svh).
4.1 Contoh kode: tipografi fluid menggunakan unit kueri penampung
.card-wrapper {
container: card / inline-size; /* shorthand for container-name / container-type */
}
@container card (inline-size > 400px) {
.content {
display: flex;
gap: 2rem;
}
}
.title {
/* Fluid type bound to the container width, not the viewport. */
font-size: clamp(1rem, 4cqi, 2rem);
}
Untuk pola gaya responsif berbasis komponen, lihat Penataan Gaya Berdasarkan Ukuran dan Penskalaan Fleksibel.
5 Overlay native, pemosisian anchor, dan konteks tumpukan
Kapan harus menggunakan setiap primitif overlay:
- Gunakan
popoveruntuk UI non-modal sementara (flyout, toast, tooltip) — berada di lapisan atas, tidak memerlukan pengelolaanz-index. - Gunakan
<dialog>dengan.showModal()untuk interaksi modal yang memerlukan penguncian fokus dan latar belakang inert. - Jangan gabungkan
popoverdan.showModal()pada elemen yang sama — keduanya adalah status runtime yang sama-sama eksklusif.
Pemosisian anchor (tata letak spasial overlay):
- Gunakan
position-area(atauanchor()pada inset) dananchor-size()untuk memosisikan dan mengukur overlay sesuai pemicunya. - Gunakan
position-try-fallbacks: flip-block(atauflip-inline) untuk mengizinkan browser mengubah posisi saat overlay melebihi area pandang. - Jangan mencampur kata kunci fisik dan logis dalam satu nilai
position-area— pilih satu sistem koordinat. - Deteksi fitur dengan
@supports (anchor-name: --x)dan berikan penggantian posisi absolut.
Untuk mengetahui detail implementasi lengkap, strategi polyfill, dan referensi nilai
popover, lihat Dialog Deklaratif dan Kontrol Popover serta Tooltip yang Memperhitungkan Posisi. Untuk pemosisian anchor yang diterapkan ke dropdown, flyout, dan indikator tab, lihat Dropdown yang Memperhatikan Area Tampilan dan Garis Bawah Tab Pemosisian Anchor.
6 Pelacakan overflow dan stabilitas tata letak
Kelola pergeseran tata letak, scrollbar, dan pemangkasan secara terprediksi.
Lakukan:
- Gunakan
overflow: autoagar scrollbar hanya muncul saat konten benar-benar meluap. - Gunakan
overflow: clipuntuk memotong konten tanpa membuat penampung scroll; pilih spillover denganoverflow-clip-margin. - Gunakan
scrollbar-gutter: stableuntuk mencadangkan ruang bagi scrollbar dan mencegah pergeseran tata letak saat konten bertambah. - Gunakan
overscroll-behavior: contain(ataunone) pada region scroll bertingkat (seperti sidebar, modal, dan daftar) untuk menghentikan rantai scroll agar tidak muncul ke halaman, atauoverscroll-behavior: chainpada wrapper scroll perantara (seperti trek geser untuk menampilkan) saat scroll berlebih harus disebarkan ke scroller ancestor tanpa memicu pantulan rubber-band lokal. Gunakan triad
-webkit-line-clamp+display: -webkit-box+-webkit-box-orient: verticaluntuk pemotongan multibaris — meskipun memiliki awalan, pola ini sepenuhnya ditentukan dan tidak digunakan lagi. Deklarasikan singkatanline-clamptanpa awalan di sampingnya; browser yang belum mendukungnya akan mengabaikan properti tersebut tanpa menimbulkan masalah. Jangan:Jangan gunakan
overflow: scrolljikaautosudah cukup —scrollmemaksa scrollbar muncul meskipun tidak ada yang perlu di-scroll.Jangan gunakan
overflow: hiddenjika Anda hanya ingin memotong —hiddenmembuat penampung scroll yang dapat di-scroll secara terprogram.
.scrollable-list {
max-block-size: 400px;
overflow-y: auto;
scrollbar-gutter: stable; /* Reserve scrollbar space. */
overscroll-behavior: contain; /* No scroll chaining into the page. */
}
.snippet {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-clamp: 3; /* Ignored where unsupported. */
overflow: clip;
}
Untuk mengetahui
overflow: clipdanoverflow-clip-marginsecara mendalam, lihat Kontrol Pemangkasan Overflow. Untuk pengalihan scroll bertingkat denganoverscroll-behavior: chaindi UI geser untuk menampilkan, lihat Geser untuk menampilkan. Untuk warna, ukuran, dan tema scrollbar, lihat Menyesuaikan warna atau ketebalan scrollbar, Mode gelap, dan Menyesuaikan scrollbar dengan preferensi kontras tinggi.
7 Mekanisme area pandang dan distribusi jalur
- Gunakan
dvh/dvwuntuk penampung tata letak seluler yang harus memperhitungkan pergeseran UI browser (penciutan/perluasan kolom URL). - Jangan gunakan
100vwuntuk tata letak lebar penuh — ini mengabaikan lebar scrollbar dan menyebabkan overflow horizontal. Sebagai gantinya, gunakan100%,100dvw, atau100svw.
Untuk titik entri desain responsif (unit area pandang dinamis, menyediakan ruang untuk media, tipografi fluid), lihat Desain responsif.
8 Jalur petak (alias masonry)
Spesifikasi ini sedang dalam pengembangan dengan nama "grid lanes" (misalnya, display: grid-lanes), sedangkan prototipe eksperimental sebelumnya menggunakan grid-template-rows: masonry.
Lakukan:
- Gunakan petak dengan
grid-auto-flow: denseuntuk pengemasan yang rapat saat ini, dengan menerima bahwa urutan DOM mungkin tidak cocok dengan urutan visual. - Gunakan multi-kolom (
columns: 3; column-gap: 1rem) untuk alur seperti masonry yang padat konten jika itemnya adalah fragmen dokumen, bukan kartu dengan bobot yang sama. - Perlakukan
grid-template-rows: masonryhanya sebagai progressive enhancement — deteksi fitur dengan@supports.
Jangan:
- Jangan kirimkan
grid-template-rows: masonrysebagai persyaratan ketat hingga target Dasar Pengukuran Anda tercapai.
.gallery { columns: 3 200px; column-gap: 1rem; }
.gallery > * { break-inside: avoid; margin-block-end: 1rem; }
@supports (grid-template-rows: masonry) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry;
gap: 1rem;
columns: unset;
}
}