Flexbox dan Grid CSS: Layout Modern untuk Pemula
Dua alat layout yang menggantikan trik-trik lama seperti float. Kamu akan memakai keduanya untuk membuat satu halaman responsif dari nol.
Oleh Afa Hernandes14 menit baca
Daftar isi
- Sebelum mulai
- Langkah 1: Tulis struktur HTML
- Langkah 2: Pasang dasar CSS
- Flexbox: menyusun elemen dalam satu arah
- Langkah 3: Header dengan Flexbox
- Langkah 4: Bagian pembuka, rata tengah
- Grid: menyusun elemen dalam baris dan kolom
- Langkah 5: Kartu menu yang menyesuaikan layar
- Langkah 6: Isi kartu, harga selalu di bawah
- Langkah 7: Lokasi, beda layout untuk HP dan laptop
- Hasil
- Kode CSS lengkap
- Flexbox atau Grid?
- Error yang sering muncul
- Langkah berikutnya: rilis dan amankan
- Pertanyaan yang sering diajukan
- Masih perlu belajar float?
- Bootstrap atau Tailwind saja, tidak perlu Flexbox dan Grid?
- Kapan perlu media query kalau Grid bisa menyesuaikan sendiri?
- Apa bedanya auto-fit dan auto-fill?
- Kesimpulan
Dulu, membuat layout dengan CSS penuh trik: float, clearfix, tabel, atau angka margin yang dihitung manual dan rusak begitu ukuran layar berubah. Sekarang ada dua alat yang memang dibuat untuk layout: Flexbox dan Grid. Keduanya didukung semua browser modern, jadi kamu bisa langsung memakainya.
Di tutorial ini kamu akan membuat halaman sederhana untuk sebuah kedai kopi: header dengan menu, bagian pembuka di tengah layar, deretan kartu menu, dan bagian lokasi. Halamannya otomatis menyesuaikan diri: empat kolom di laptop, satu kolom di HP.
Sebelum mulai
- Editor kode, misalnya VS Code. Cara menyiapkannya ada di tutorial VS Code dan terminal.
- Browser modern. Contoh di tutorial ini diuji di Chrome.
- Tahu sedikit HTML (tag, atribut,
class). Kalau belum, baca dulu bagian “Cara kerja web” di roadmap web developer.
Buat folder kopi-senja berisi dua file kosong: index.html dan style.css.
Langkah 1: Tulis struktur HTML
Mulai dari isinya dulu, tampilannya belakangan. Pakai tag yang sesuai maknanya: header untuk kepala halaman, nav untuk menu, main untuk isi utama, section untuk tiap bagian, article untuk tiap kartu, dan footer untuk kaki halaman. Tag seperti ini disebut HTML semantik. Pembaca layar (screen reader) dan mesin pencari jadi lebih mudah memahami halamanmu.
<!doctype html><html lang="id"><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Kedai Kopi Senja</title> <link rel="stylesheet" href="style.css"></head><body> <header class="site-header"> <a class="logo" href="#">Kopi Senja</a> <nav> <ul class="nav-list"> <li><a href="#menu">Menu</a></li> <li><a href="#lokasi">Lokasi</a></li> <li><a href="#kontak">Kontak</a></li> </ul> </nav> </header>
<main> <section class="hero"> <h1>Kopi enak, harga teman.</h1> <p>Diseduh setiap pagi dari biji kopi lokal.</p> <a class="button" href="#menu">Lihat menu</a> </section>
<section id="menu" class="menu"> <h2>Menu favorit</h2> <div class="card-grid"> <article class="card"> <h3>Kopi susu</h3> <p>Espresso, susu segar, gula aren.</p> <p class="price">Rp18.000</p> </article> <article class="card"> <h3>Americano</h3> <p>Espresso dan air panas, tanpa gula.</p> <p class="price">Rp15.000</p> </article> <article class="card"> <h3>Matcha latte</h3> <p>Matcha Jepang dengan susu segar, bisa panas atau dingin.</p> <p class="price">Rp22.000</p> </article> <article class="card"> <h3>Croissant</h3> <p>Dipanggang setiap pagi, renyah di luar.</p> <p class="price">Rp25.000</p> </article> </div> </section>
<section id="lokasi" class="lokasi"> <div> <h2>Lokasi</h2> <p>Jl. Contoh No. 12, dekat kampus. Parkir motor tersedia.</p> </div> <div id="kontak"> <h2>Kontak</h2> <p>Pesan antar lewat WhatsApp kedai, setiap hari sampai pukul 21.00.</p> </div> </section> </main>
<footer class="site-footer"> <p>Buka setiap hari, 07.00–22.00</p> </footer></body></html>Perhatikan baris <meta name="viewport" …>. Tanpa baris ini, browser HP menganggap halamanmu dibuat untuk layar lebar lalu mengecilkannya, sehingga tulisannya jadi kecil sekali. Baris ini wajib ada di setiap halaman yang ingin tampil baik di HP.
Buka index.html di browser. Isinya sudah tampil, tapi masih polos dan bertumpuk ke bawah. Itu normal: kita belum menulis CSS apa pun.
Langkah 2: Pasang dasar CSS
*,*::before,*::after { box-sizing: border-box;}
body { margin: 0; font-family: system-ui, sans-serif; line-height: 1.6; color: #1f2328; background: #fbf9f6;}box-sizing: border-box membuat width sebuah elemen sudah termasuk padding dan border-nya. Tanpa ini, kotak selebar 300px dengan padding 20px sebenarnya jadi 340px, dan layout mudah meleber. Hampir semua proyek modern memasang aturan ini di awal.
Flexbox: menyusun elemen dalam satu arah
Flexbox dipakai untuk menyusun elemen dalam satu baris atau satu kolom. Kamu memasang display: flex di elemen pembungkus (disebut flex container), lalu anak-anaknya (flex item) otomatis berjajar.
Ada dua sumbu yang perlu dipahami:
| Properti | Mengatur | Nilai yang sering dipakai |
|---|---|---|
flex-direction |
arah susunan | row (bawaan, mendatar), column (menurun) |
justify-content |
posisi di sumbu utama (searah flex-direction) |
flex-start, center, space-between |
align-items |
posisi di sumbu silang (tegak lurus sumbu utama) | stretch (bawaan), center, flex-start |
gap |
jarak antar-item | 1rem, 20px |
flex-wrap |
boleh pindah baris kalau tidak muat | wrap |
Kalau flex-direction: row, sumbu utamanya mendatar, jadi justify-content mengatur posisi kiri-kanan dan align-items mengatur atas-bawah. Kalau column, keduanya bertukar.
Langkah 3: Header dengan Flexbox
Kita ingin logo di kiri dan menu di kanan, sejajar di tengah secara vertikal:
/* Header: logo di kiri, menu di kanan (Flexbox) */.site-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; padding: 1rem 1.5rem; background: #3b2a20;}
.logo { color: #fff; font-weight: 700; font-size: 1.25rem; text-decoration: none;}
.nav-list { display: flex; gap: 1.25rem; margin: 0; padding: 0; list-style: none;}
.nav-list a { color: #f3e3d3; text-decoration: none;}justify-content: space-betweenmendorong item pertama (logo) ke ujung kiri dan item terakhir (nav) ke ujung kanan.align-items: centermembuat keduanya sejajar di tengah secara vertikal, walaupun ukuran hurufnya berbeda.flex-wrap: wrapmembolehkan menu turun ke baris baru di layar yang sangat sempit, daripada keluar dari layar..nav-listjuga diberidisplay: flex. Flexbox bisa bersarang: satu elemen bisa menjadi flex item bagi induknya sekaligus flex container bagi anak-anaknya.
gap menggantikan kebiasaan lama memberi margin-right ke setiap item lalu menghapusnya di item terakhir.
Langkah 4: Bagian pembuka, rata tengah
Menaruh sesuatu tepat di tengah dulu terkenal sulit di CSS. Dengan Flexbox cukup beberapa baris:
/* Hero: isi di tengah (Flexbox arah kolom) */.hero { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75rem; min-height: 50vh; padding: 3rem 1.5rem; text-align: center;}
.hero h1 { margin: 0; font-size: clamp(2rem, 6vw, 3.5rem); line-height: 1.15;}
.hero p { margin: 0;}
.button { padding: 0.75rem 1.5rem; border-radius: 999px; background: #b45309; color: #fff; font-weight: 600; text-decoration: none;}Karena arahnya column, justify-content: center menaruh isinya di tengah secara vertikal (setinggi 50vh, setengah tinggi layar), dan align-items: center menaruhnya di tengah secara horizontal.
clamp(2rem, 6vw, 3.5rem) membuat ukuran judul ikut membesar sesuai lebar layar (6vw, 6% dari lebar layar), tapi tidak pernah lebih kecil dari 2rem atau lebih besar dari 3.5rem. Satu baris ini menggantikan beberapa media query.
Grid: menyusun elemen dalam baris dan kolom
Grid dipakai untuk layout dua dimensi: baris dan kolom sekaligus. Kamu menentukan kolomnya di elemen pembungkus, lalu anak-anaknya otomatis mengisi sel satu per satu.
.contoh { display: grid; grid-template-columns: 1fr 1fr 1fr; /* tiga kolom sama lebar */ gap: 1rem;}Satuan fr (fraction) berarti “bagian dari sisa ruang”. 1fr 1fr 1fr membagi lebar jadi tiga bagian sama, sedangkan 2fr 1fr membuat kolom pertama dua kali lebih lebar dari kolom kedua.
Langkah 5: Kartu menu yang menyesuaikan layar
Untuk kartu menu, kita tidak ingin menentukan jumlah kolom secara pasti. Di laptop muat empat, di tablet tiga, di HP cukup satu. Grid bisa menghitungnya sendiri:
/* Menu: kartu yang menyesuaikan lebar layar (Grid) */.menu { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem 4rem;}
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.25rem;}Baca repeat(auto-fit, minmax(220px, 1fr)) dari dalam ke luar:
minmax(220px, 1fr): setiap kolom minimal220px, dan boleh melebar mengisi sisa ruang.repeat(auto-fit, …): buat kolom sebanyak yang muat.
Hasilnya, browser menghitung sendiri berapa kolom 220px yang muat di layar, lalu melebarkannya supaya rata. Saat diuji di Chrome, lebar 1280 px menghasilkan empat kolom, 820 px tiga kolom, dan 390 px (ukuran HP) satu kolom. Semua tanpa media query.
max-width: 1100px dan margin: 0 auto membatasi lebar isi dan menaruhnya di tengah, supaya kartu tidak melebar sampai ujung layar monitor besar.
Langkah 6: Isi kartu, harga selalu di bawah
Kalau deskripsi kartu panjangnya berbeda-beda, harga di setiap kartu jadi tidak sejajar. Grid sudah membuat semua kartu dalam satu baris sama tinggi, jadi tinggal mendorong harga ke dasar kartu dengan Flexbox:
.card { display: flex; flex-direction: column; padding: 1.25rem; border: 1px solid #e7dfd6; border-radius: 16px; background: #fff;}
.card h3,.card p { margin: 0 0 0.5rem;}
.card .price { margin-top: auto; font-weight: 700; color: #b45309;}Di dalam flex container, margin-top: auto menyerap semua ruang kosong di atas elemen itu, sehingga harga terdorong ke bawah. Ini contoh yang bagus bahwa Grid dan Flexbox bukan saingan: Grid menyusun kartunya, Flexbox menyusun isi tiap kartu.
Selektornya sengaja ditulis .card .price, bukan .price saja. Alasannya dibahas di bagian error di bawah.
Langkah 7: Lokasi, beda layout untuk HP dan laptop
Bagian lokasi dan kontak cukup satu kolom di HP, tapi lebih enak dua kolom di layar lebar. Di sini kita memakai media query, aturan CSS yang hanya berlaku pada ukuran layar tertentu:
/* Lokasi & kontak: satu kolom di HP, dua kolom di layar lebar */.lokasi { display: grid; gap: 1.25rem; max-width: 1100px; margin: 0 auto; padding: 0 1.5rem 4rem;}
@media (min-width: 700px) { .lokasi { grid-template-columns: 1fr 1fr; }}
.site-footer { padding: 1.5rem; text-align: center; background: #3b2a20; color: #f3e3d3;}Gaya dasarnya ditulis untuk HP (satu kolom, bawaan grid), lalu @media (min-width: 700px) menambahkan dua kolom untuk layar yang lebarnya minimal 700 px. Cara ini disebut mobile-first: mulai dari layar kecil, lalu tambahkan aturan untuk layar yang lebih besar.
Hasil
Simpan kedua file, lalu muat ulang browser. Di laptop, kartu menu tampil empat kolom dengan harga yang sejajar di dasar kartu:

Di HP, kartu otomatis tersusun satu kolom dan bagian lokasi menjadi satu kolom:

Untuk mencoba berbagai ukuran layar di laptop, buka DevTools (F12), lalu klik ikon Toggle device toolbar atau tekan Ctrl+Shift+M.
Kode CSS lengkap
*,*::before,*::after { box-sizing: border-box;}
body { margin: 0; font-family: system-ui, sans-serif; line-height: 1.6; color: #1f2328; background: #fbf9f6;}
/* Header: logo di kiri, menu di kanan (Flexbox) */.site-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem; padding: 1rem 1.5rem; background: #3b2a20;}
.logo { color: #fff; font-weight: 700; font-size: 1.25rem; text-decoration: none;}
.nav-list { display: flex; gap: 1.25rem; margin: 0; padding: 0; list-style: none;}
.nav-list a { color: #f3e3d3; text-decoration: none;}
/* Hero: isi di tengah (Flexbox arah kolom) */.hero { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75rem; min-height: 50vh; padding: 3rem 1.5rem; text-align: center;}
.hero h1 { margin: 0; font-size: clamp(2rem, 6vw, 3.5rem); line-height: 1.15;}
.hero p { margin: 0;}
.button { padding: 0.75rem 1.5rem; border-radius: 999px; background: #b45309; color: #fff; font-weight: 600; text-decoration: none;}
/* Menu: kartu yang menyesuaikan lebar layar (Grid) */.menu { max-width: 1100px; margin: 0 auto; padding: 2rem 1.5rem 4rem;}
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.25rem;}
.card { display: flex; flex-direction: column; padding: 1.25rem; border: 1px solid #e7dfd6; border-radius: 16px; background: #fff;}
.card h3,.card p { margin: 0 0 0.5rem;}
.card .price { margin-top: auto; font-weight: 700; color: #b45309;}
/* Lokasi & kontak: satu kolom di HP, dua kolom di layar lebar */.lokasi { display: grid; gap: 1.25rem; max-width: 1100px; margin: 0 auto; padding: 0 1.5rem 4rem;}
@media (min-width: 700px) { .lokasi { grid-template-columns: 1fr 1fr; }}
.site-footer { padding: 1.5rem; text-align: center; background: #3b2a20; color: #f3e3d3;}Flexbox atau Grid?
| Pakai | Kalau | Contoh |
|---|---|---|
| Flexbox | elemen berjajar dalam satu arah, dan ukurannya ditentukan isinya | navbar, deretan tombol, isi sebuah kartu, menaruh sesuatu di tengah |
| Grid | elemen disusun dalam baris dan kolom sekaligus | daftar kartu produk, galeri foto, kerangka halaman (sidebar + isi) |
Kalau ragu, mulai dengan Flexbox. Begitu kamu mulai mengatur lebar setiap item supaya kolom-kolomnya sejajar, itu tanda kamu sebenarnya butuh Grid.
Error yang sering muncul
CSS tidak menampilkan pesan error. Kalau ada yang salah, aturannya diam-diam tidak berlaku. Ini gejala yang paling sering:
justify-content atau align-items tidak berpengaruh apa-apa. Kedua properti ini hanya bekerja di elemen yang punya display: flex atau display: grid. Pastikan kamu memasangnya di elemen pembungkus, bukan di anaknya.
Harga di kartu tidak sejajar walaupun sudah diberi margin-top: auto. Kemungkinan besar aturannya kalah oleh aturan lain. Kalau kamu menulis .price { margin-top: auto; }, aturan .card p { margin: 0 0 0.5rem; } menang, karena selektor .card p lebih spesifik (satu class dan satu tag) daripada .price (satu class saja). Saat diuji, harga kartu yang deskripsinya lebih panjang jadi turun sendiri. Solusinya, tulis .card .price. Klik kanan elemennya, pilih Inspect, dan DevTools akan menunjukkan aturan mana yang dicoret.
Halaman tampil kecil sekali di HP. Tag <meta name="viewport" content="width=device-width, initial-scale=1"> belum ada di <head>.
Ada scroll ke samping di HP. Biasanya ada elemen dengan lebar tetap yang lebih besar dari layar, misalnya width: 500px atau gambar tanpa max-width: 100%. Ganti dengan max-width, atau biarkan Grid dan Flexbox yang mengatur lebarnya.
Perubahan CSS tidak muncul. Periksa nama file di <link rel="stylesheet" href="style.css">, lalu muat ulang paksa dengan Ctrl+Shift+R supaya browser tidak memakai versi lama yang tersimpan.
Langkah berikutnya: rilis dan amankan
Halaman ini hanya berisi HTML dan CSS, jadi bisa langsung online gratis. Tarik folder kopi-senja ke Cloudflare Pages seperti di deploy pertama, dan dalam beberapa menit kamu punya link yang bisa dibagikan.
Dari sisi keamanan, halaman statis seperti ini risikonya kecil karena tidak ada data pengguna yang diproses. Yang perlu diingat: semua isi folder yang kamu unggah bisa dibaca siapa saja, jadi jangan ikutkan file pribadi. Begitu halamanmu mulai menerima input pengguna, pelajari XSS dan CSRF.
Pertanyaan yang sering diajukan
Masih perlu belajar float?
Untuk layout, tidak. float sekarang hanya dipakai untuk tujuan aslinya: membuat teks mengalir di sekeliling gambar. Kamu cukup tahu artinya kalau menemukannya di kode lama.
Bootstrap atau Tailwind saja, tidak perlu Flexbox dan Grid?
Keduanya justru memakai Flexbox dan Grid di baliknya. Class seperti flex dan justify-between di Tailwind adalah display: flex dan justify-content: space-between. Kalau konsepnya sudah paham, belajar Tailwind di level berikutnya jauh lebih cepat.
Kapan perlu media query kalau Grid bisa menyesuaikan sendiri?
Saat susunannya memang harus berubah, bukan hanya jumlah kolomnya. Misalnya menu disembunyikan di HP, atau sidebar pindah ke bawah isi. Untuk daftar kartu, repeat(auto-fit, minmax(…)) biasanya sudah cukup.
Apa bedanya auto-fit dan auto-fill?
Bedanya terlihat saat itemnya sedikit. auto-fit melebarkan item yang ada supaya memenuhi baris, sedangkan auto-fill tetap menyisakan kolom kosong. Untuk daftar yang isinya tetap, seperti empat kartu menu ini, auto-fit cocok. Untuk daftar yang jumlahnya berubah-ubah, misalnya hasil pencarian, pakai auto-fill supaya satu hasil tidak melebar selebar layar.
Kesimpulan
Flexbox menyusun elemen dalam satu arah, Grid menyusun elemen dalam baris dan kolom, dan keduanya paling kuat kalau dipakai bersama. Dengan repeat(auto-fit, minmax(…)), gap, dan margin-top: auto, kamu sudah bisa membuat sebagian besar layout yang kamu temui sehari-hari.
Halaman Kopi Senja masih statis. Di langkah berikutnya di jalur Web Developer Modern, kamu akan membuatnya hidup dengan pencarian dan keranjang belanja lewat JavaScript modern.



