Kenapa ini penting
Dulu developer menyusun layout dengan float, table, dan trik clearfix yang rumit. Sekarang kita punya dua alat yang dirancang khusus untuk tata letak: Flexbox dan CSS Grid. Hampir semua layout modern, dari navbar, kartu produk, dashboard, sampai halaman majalah, dibangun dengan kombinasi keduanya.
Analogi sederhananya: Flexbox seperti mengatur orang dalam satu antrean, bisa dirapatkan, direnggangkan, atau dibagi rata. Grid seperti papan catur atau denah lantai: kamu menentukan baris dan kolom, lalu menaruh elemen di kotak-kotaknya. Flexbox bekerja dalam satu dimensi (baris atau kolom), Grid dalam dua dimensi (baris dan kolom sekaligus).
Konsep inti
Flexbox
Aktifkan dengan display: flex pada container (induk). Anak-anak langsungnya otomatis menjadi flex item.
Dua sumbu penting:
- Main axis (sumbu utama): arah item disusun, diatur oleh
flex-direction. - Cross axis (sumbu silang): tegak lurus terhadap main axis.
Properti pada container:
| Properti | Nilai umum | Fungsi |
|---|---|---|
flex-direction |
row (default), column, row-reverse |
Arah main axis |
justify-content |
flex-start, center, space-between, space-around, space-evenly |
Perataan di main axis |
align-items |
stretch (default), center, flex-start, flex-end, baseline |
Perataan di cross axis |
flex-wrap |
nowrap (default), wrap |
Boleh pindah baris atau tidak |
gap |
1rem |
Jarak antar item |
align-content |
sama seperti justify | Perataan antar baris saat wrap |
Properti pada item:
flex-grow: seberapa rakus item mengambil sisa ruang (0 = tidak mau tumbuh).flex-shrink: seberapa rela item mengecil saat ruang kurang (default 1).flex-basis: ukuran awal sebelum tumbuh atau menyusut.- Shorthand
flex:flex: 1artinya1 1 0%(tumbuh rata),flex: noneartinya tidak tumbuh dan tidak menyusut. align-self: menimpaalign-itemsuntuk satu item.order: mengubah urutan tampilan (hati-hati, urutan baca screen reader tetap mengikuti HTML).
Trik klasik: margin-left: auto pada sebuah item mendorong item itu dan semua item setelahnya ke ujung kanan. Cocok untuk tombol login di navbar.
CSS Grid
Aktifkan dengan display: grid pada container.
grid-template-columns: 200px 1fr 1fr;membuat tiga kolom. Unitfr(fraction) membagi sisa ruang secara proporsional:1fr 2frartinya kolom kedua dua kali lebar kolom pertama.repeat(3, 1fr)adalah singkatan untuk1fr 1fr 1fr.grid-template-rowsmengatur baris. Kalau item melebihi baris yang didefinisikan, Grid membuat baris implisit yang tingginya diaturgrid-auto-rows.gap,row-gap,column-gapuntuk jarak.
Menempatkan item:
- Berdasarkan garis:
grid-column: 1 / 3;(dari garis 1 sampai garis 3, berarti dua kolom) ataugrid-column: span 2;.1 / -1berarti dari garis pertama sampai terakhir (lebar penuh). - Berdasarkan nama area dengan
grid-template-areas, yang membuat layout bisa "digambar" seperti peta ASCII:
.halaman {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
Titik . dalam template berarti sel kosong. Setiap baris string harus punya jumlah kolom yang sama, dan area harus berbentuk persegi panjang.
Responsif tanpa media query: auto-fit dan minmax
Pola ini wajib kamu hafal:
.galeri {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
Bacanya: "buat kolom sebanyak yang muat; setiap kolom minimal 220px dan maksimal 1fr." Di layar 1200px kamu dapat sekitar lima kolom, di HP 360px satu kolom, tanpa satu pun media query.
Perbedaan auto-fit dan auto-fill terlihat ketika item sedikit: auto-fill mempertahankan kolom kosong (item tetap selebar minimal), sedangkan auto-fit melipat kolom kosong sehingga item yang ada melebar mengisi baris.
Agar kolom tidak meluber di layar sangat sempit, gunakan minmax(min(220px, 100%), 1fr).
Perataan di Grid
justify-itemsdanalign-itemsmeratakan isi di dalam sel.place-items: centeradalah singkatan keduanya, cara tercepat menaruh sesuatu tepat di tengah.justify-selfdanalign-selfuntuk satu item.
Kapan Flexbox, kapan Grid?
| Situasi | Pilihan |
|---|---|
| Navbar, deretan tombol, tag, ikon dan teks | Flexbox |
| Isi menentukan ukuran (konten-dulu) | Flexbox |
| Galeri kartu dengan kolom sejajar | Grid |
| Kerangka halaman (header, sidebar, main, footer) | Grid |
| Layout menentukan ukuran (struktur-dulu) | Grid |
Keduanya sering dipakai bersama: Grid untuk kerangka halaman, Flexbox di dalam tiap kartu.
Contoh kode
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dashboard Layout</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, sans-serif; }
/* ===== Kerangka halaman dengan Grid template areas ===== */
.halaman {
min-height: 100vh;
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; background: #1e293b; color: white; }
.sidebar { grid-area: sidebar; background: #f1f5f9; padding: 1rem; }
.main { grid-area: main; padding: 1.5rem; }
.footer { grid-area: footer; background: #e2e8f0; padding: 1rem; text-align: center; }
/* ===== Navbar dengan Flexbox ===== */
.nav {
display: flex;
align-items: center; /* rata tengah vertikal */
gap: 1.5rem;
padding: 1rem 1.5rem;
}
.nav__logo { font-weight: 800; }
.nav__link { color: inherit; text-decoration: none; }
.nav__masuk { margin-left: auto; } /* dorong ke ujung kanan */
/* ===== Galeri kartu responsif tanpa media query ===== */
.galeri {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
gap: 1rem;
}
.kartu--lebar { grid-column: span 2; } /* satu kartu mengambil dua kolom */
/* ===== Isi kartu dengan Flexbox kolom ===== */
.kartu {
display: flex;
flex-direction: column;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 12px;
}
.kartu__isi { flex: 1; } /* isi mengambil sisa ruang... */
.kartu__aksi { /* ...sehingga tombol selalu menempel di bawah */
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 1rem;
}
</style>
</head>
<body>
<div class="halaman">
<header class="header">
<nav class="nav" aria-label="Navigasi utama">
<span class="nav__logo">KopiDash</span>
<a class="nav__link" href="#">Ringkasan</a>
<a class="nav__link" href="#">Laporan</a>
<a class="nav__link nav__masuk" href="#">Masuk</a>
</nav>
</header>
<aside class="sidebar">Menu samping</aside>
<main class="main">
<h1>Penjualan minggu ini</h1>
<div class="galeri">
<article class="kartu kartu--lebar">
<div class="kartu__isi"><h2>Total</h2><p>Rp12.500.000</p></div>
<div class="kartu__aksi"><span>+12%</span><button>Detail</button></div>
</article>
<article class="kartu">
<div class="kartu__isi"><h2>Kopi aren</h2><p>420 gelas</p></div>
<div class="kartu__aksi"><span>+8%</span><button>Detail</button></div>
</article>
<article class="kartu">
<div class="kartu__isi"><h2>Americano</h2><p>180 gelas, deskripsi lebih panjang dari kartu lain</p></div>
<div class="kartu__aksi"><span>-2%</span><button>Detail</button></div>
</article>
</div>
</main>
<footer class="footer">© 2026 KopiDash</footer>
</div>
</body>
</html>
<!-- → Header gelap di atas, sidebar kiri 220px, konten di kanan, footer di bawah.
"Masuk" menempel di kanan navbar. Kartu menyusun diri otomatis sesuai lebar layar,
dan tombol "Detail" di semua kartu sejajar di bawah walau panjang teksnya berbeda. -->
Gunakan DevTools: klik label grid atau flex di samping elemen pada panel Elements untuk menampilkan overlay garis grid dan arah flex.
Kesalahan umum
- Memasang
justify-contentpada item, bukan container. Cara benar: properti perataan utama dipasang di elemen yang punyadisplay: flex/grid. - Bingung sumbu saat
flex-direction: column. Di mode kolom,justify-contentmengatur vertikal danalign-itemsmengatur horizontal. Cara benar: ingat bahwa justify selalu mengikuti main axis. - Memakai margin untuk jarak antar item. Cara benar: pakai
gap, yang tidak menambah jarak di tepi luar. - Teks panjang membuat flex item meluber. Penyebabnya
min-width: autobawaan flex item. Cara benar: berimin-width: 0pada item yang berisi teks panjang. grid-template-areasdengan jumlah kolom tidak konsisten atau area berbentuk L. Cara benar: setiap string sama panjang kolomnya dan setiap area berbentuk persegi panjang.
Latihan
- Mudah, Taruh sebuah kotak tepat di tengah layar (horizontal dan vertikal) dengan dua cara: Flexbox dan Grid.
- Sedang, Buat galeri foto responsif yang minimal 180px per kolom dan otomatis menyesuaikan jumlah kolom, dengan jarak 12px.
- Menantang, Buat layout "holy grail" dengan
grid-template-areas: header, nav kiri, main, aside kanan, footer. Kolom samping 200px, main fleksibel.
Lihat solusi
/* Soal 1 */
.tengah-flex {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.tengah-grid {
min-height: 100vh;
display: grid;
place-items: center;
}
/* Soal 2 */
.galeri-foto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
gap: 12px;
}
.galeri-foto img {
width: 100%;
aspect-ratio: 1; /* persegi */
object-fit: cover;
}
/* Soal 3 */
.holy-grail {
min-height: 100vh;
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
gap: 1rem;
}
.holy-grail > header { grid-area: header; }
.holy-grail > nav { grid-area: nav; }
.holy-grail > main { grid-area: main; }
.holy-grail > aside { grid-area: aside; }
.holy-grail > footer { grid-area: footer; }
/* → Tiga kolom di tengah, header dan footer melebar penuh */
Ringkasan
- Flexbox satu dimensi (antrean), Grid dua dimensi (denah). Sering dipakai bersama.
justify-contentmengikuti main axis,align-itemsmengikuti cross axis;gapuntuk jarak.flex: 1membuat item mengisi sisa ruang;margin-left: automendorong item ke ujung.- Grid: unit
fr,repeat(),grid-template-areasuntuk layout yang bisa "digambar". repeat(auto-fit, minmax(min(Xpx, 100%), 1fr))membuat galeri responsif tanpa media query.