Ilustrasi kotak-kotak elastis berbaris dengan panah alignment

Selama puluhan tahun, menengahkan sebuah kotak secara vertikal adalah meme di kalangan web developer: hal yang seharusnya sepele tapi butuh hack aneh-aneh. Lalu datanglah Flexbox, dan masalah itu selesai dalam tiga baris. Ini episode kelima dari seri CSS Basic, dan boleh dibilang materi paling transformatif di seri ini. Setelah paham Flexbox, cara kamu memandang layout berubah: bukan lagi mengatur tiap kotak satu per satu, tapi mengatur hubungan antar kotak di dalam wadahnya.

Dua persepsi salah yang perlu diluruskan. Pertama, banyak pemula mengira Flexbox itu "pengganti semua cara layout lama" sehingga dipakai untuk segalanya, termasuk layout dua dimensi yang rumit. Padahal Flexbox dirancang untuk layout satu dimensi: satu baris ATAU satu kolom. Untuk baris DAN kolom sekaligus, ada CSS Grid (episode berikutnya). Kedua, banyak yang menghafal properti Flexbox tanpa paham konsep sumbunya, akibatnya justify-content dan align-items tertukar terus. Padahal kalau paham sumbunya, tidak ada yang perlu dihafal.

Konsep Inti: Wadah yang Mengatur Isinya

Cara berpikir Flexbox dibalik dari cara lama. Dulu kamu mengatur tiap item satu per satu. Di Flexbox, kamu memberi perintah ke wadahnya (flex container), dan semua isinya (flex items) menuruti. Satu baris mengaktifkan semuanya:

.wadah {
  display: flex;
}

Sejak baris itu ditulis, semua anak langsung dari .wadah berbaris horizontal secara otomatis. Kamu tidak perlu mengatur tiap anak. Analogi yang pas: kamu adalah pelatih, bukan pemain. Pelatih tidak berlari ke tiap pemain untuk mengatur posisinya, pelatih memberi instruksi ke tim dan tim yang bergerak.

Sekarang konsep kuncinya: sumbu. Flexbox punya dua sumbu yang selalu tegak lurus:

  • Main axis (sumbu utama): arah barisannya. Default-nya horizontal (kiri ke kanan), diatur oleh flex-direction.
  • Cross axis (sumbu silang): arah tegak lurus main axis. Default-nya vertikal.

Dua properti alignment bekerja pada sumbu yang berbeda, dan inilah yang sering tertukar:

  • justify-content: mengatur posisi item di sepanjang main axis.
  • align-items: mengatur posisi item di sepanjang cross axis.

Nilai-nilainya mirip: flex-start (rapat ke awal), flex-end (rapat ke akhir), center (tengah), space-between (item pertama dan terakhir menempel ke tepi, sisa ruang dibagi rata di antaranya), space-around dan space-evenly (variasi pembagian ruang).

Berhenti dan tebak dulu! Wadah ini memakai flex-direction: column. Ke mana item-itemnya bergerak kalau kamu menulis justify-content: center?

.wadah {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
Jawaban: bergerak ke tengah secara VERTIKAL. Ini jebakan klasiknya. justify-content selalu mengikuti main axis, dan flex-direction: column memutar main axis menjadi vertikal. Jadi "justify" tidak selalu horizontal. Kalau kamu menghafal "justify = horizontal", kamu akan salah setiap kali direction-nya column. Pahami sumbunya, jangan hafalkan arahnya.

Tiga Baris Ajaib: Menengahkan Apapun

Pola paling terkenal di Flexbox, yang menyelesaikan meme puluhan tahun itu:

.tengah {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Apapun yang kamu taruh di dalam .tengah akan tepat di tengah layar, horizontal dan vertikal. Tiga baris, tanpa hack, tanpa perhitungan manual. min-height: 100vh memberi wadah tinggi setinggi layar (vh = persen dari tinggi viewport) supaya "tengah vertikal" punya acuan.

Pola Wajib: Navbar, Kolom, dan Kartu

Tiga pola ini menutupi 80 persen kebutuhan layout komponen di web nyata.

Pola 1: Navbar. Logo di kiri, menu di kanan, semuanya sejajar tengah secara vertikal.

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 24px;
}
.navbar ul {
  display: flex;
  gap: 24px;
  list-style: none;
}

Perhatikan gap: memberi jarak antar item tanpa margin manual. Jauh lebih bersih daripada memberi margin ke tiap item lalu menghapus margin item terakhir.

Pola 2: Kolom sama tinggi. Tiga kartu yang tingginya selalu sama walau isinya beda panjang, masalah yang dulu butuh trik curang.

.kolom {
  display: flex;
  gap: 16px;
}
.kolom > article {
  flex: 1;   /* berbagi ruang sisa sama rata */
}

flex: 1 pada item artinya "ambil ruang sisa yang tersedia, dibagi rata dengan saudaramu". Dan karena default align-items adalah stretch, semua kartu otomatis sama tinggi mengikuti yang tertinggi.

Pola 3: Kartu responsif yang melipat sendiri.

.galeri {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.kartu {
  flex: 1 1 240px;  /* boleh tumbuh, boleh susut, minimal 240px */
}

flex-wrap: wrap mengizinkan item turun ke baris baru kalau tidak muat, dan flex-basis 240px menjadi "lebar ideal" tiap kartu. Hasilnya: di layar lebar tampil 4 kolom, di HP otomatis jadi 1 kolom, tanpa media query sama sekali.

Berhenti dan tebak dulu! Apa beda space-between dan space-around pada justify-content?

Jawaban: space-between menempelkan item pertama dan terakhir ke tepi wadah, ruang hanya ada DI ANTARA item. Sedangkan space-around memberi ruang di sekitar tiap item termasuk di tepi, sehingga ruang di tepi hanya setengah dari ruang antar item. Untuk navbar (logo kiri mentok, menu kanan mentok), space-between yang tepat. Untuk galeri yang butuh napas di semua sisi, space-around atau space-evenly lebih cocok.

Kuis cepat: Kapan sebaiknya memakai Flexbox?

Properti Item: flex-grow, flex-shrink, flex-basis

Sejauh ini kita mengatur wadahnya. Tapi tiap item juga punya tiga properti pengatur dirinya sendiri, yang sering ditulis ringkas sebagai flex:

  • flex-grow: "kalau ada ruang sisa, seberapa rakus aku mengambilnya?" Nilai 0 (default) artinya tidak mau tumbuh. Nilai 1 artinya ikut berebut ruang sisa.
  • flex-shrink: "kalau ruang kurang, seberapa rela aku menyusut?" Default 1, artinya mau menyusut. Nilai 0 artinya menolak menyusut.
  • flex-basis: "ukuran idealku sebelum ruang sisa dibagi-bagi." Bisa px atau persen, seperti width versi flex.

Shorthand flex: 1 artinya flex-grow: 1; flex-shrink: 1; flex-basis: 0. Sedangkan flex: 1 1 240px artinya tumbuh ya, susut ya, ukuran ideal 240px. Contoh praktis: sidebar tetap 240px yang tidak boleh menyusut, konten mengisi sisanya.

.tata-letak { display: flex; }
.sidebar { flex: 0 0 240px; }  /* diam di 240px, tidak tumbuh tidak susut */
.konten  { flex: 1; }          /* ambil semua sisa ruang */

Analogi berbagi kue: flex-basis adalah potongan awal tiap orang, flex-grow menentukan siapa dapat sisa kue lebih banyak, flex-shrink menentukan siapa yang porsinya dipotong kalau kue kurang. Ada juga align-self untuk satu item yang mau menyimpang dari aturan align-items wadahnya, seperti satu murid yang duduknya beda dari barisan.

Berhenti dan tebak dulu! Wadah flex berisi dua item. Item A: flex: 1. Item B: flex: 2. Wadahnya 900px dan tidak ada gap. Berapa lebar masing-masing?

Jawaban: A = 300px, B = 600px. Karena flex: 1 dan flex: 2 berarti basis 0 dan ruang sisa dibagi dengan rasio 1:2. Total 3 bagian, tiap bagian 300px. Inilah cara membuat kolom proporsional tanpa menghitung persen: tulis rasionya, biarkan browser yang menghitung. Mau sidebar:konten = 1:3? Tulis flex: 1 dan flex: 3, selesai.

Latihan: Sulap Halaman Profilmu

Saatnya mengganti hack lama dengan Flexbox di halaman profilmu:

  1. Navbar Flexbox: ubah nav-mu menjadi flex dengan justify-content: space-between dan align-items: center. Taruh nama di kiri, daftar link di kanan dalam satu ul yang juga flex dengan gap. Hapus trik margin atau float lama kalau ada.
  2. Kartu sama tinggi: bungkus kartu-kartu keahlianmu dalam satu wadah flex dengan gap, beri tiap kartu flex: 1. Isi satu kartu dengan teks panjang dan satu dengan teks pendek, lalu perhatikan tingginya tetap sama.
  3. Eksperimen sumbu: duplikat satu wadah flex kecil, ubah flex-direction-nya menjadi column, lalu amati bagaimana justify-content: center tiba-tiba bekerja vertikal. Tulis di catatanmu satu kalimat yang menjelaskan kenapa ini terjadi.
  4. Tantangan: buat section "Galeri" baru berisi 6 kotak memakai pola flex-wrap: wrap + flex: 1 1 200px. Kecilkan-besarkan jendela browser dan hitung berapa kolom yang tampil di tiap ukuran. Jangan cuma baca polanya, rasakan dia bekerja.

Di episode berikutnya sekaligus penutup seri CSS Basic, CSS Grid dan Proyek Landing Page Sederhana, kamu akan belajar senjata layout dua dimensi: mendefinisikan baris dan kolom seperti menggambar denah, menempatkan elemen tepat di petaknya, dan menggabungkan semuanya menjadi satu landing page utuh. Flexbox untuk komponen, Grid untuk struktur, ingat-ingat itu.