Coba hitung sudah berapa episode kita menyusun halaman ini. Struktur sejak Session 1, kartu di Episode 2.02, kolom baca yang nyaman di Episode 2.03. Tetapi ada satu hal yang belum pernah kita lakukan: meletakkan dua kotak berdampingan.

Semua element di halaman kita tersusun menurun, satu di bawah yang lain, seperti tumpukan buku. Itu perilaku bawaan browser, dan untuk sebagian besar konten memang pas. Tetapi nama situs dan menu navigasi rasanya lebih pantas berdiri satu baris. Dua kartu kita juga cukup ramping untuk duduk bersebelahan.

Mengatur peletakan kotak-kotak di halaman punya nama: layout, alias tata letak. Dan CSS modern menyediakan dua alat utama untuknya: flexbox dan grid.

Episode ini memperkenalkan keduanya secukupnya, lalu satu tamu istimewa: element HTML yang sejak Session 1 sengaja kita simpan, karena baru hari ini ia benar-benar dibutuhkan.

Yang Akan Dipelajari

Di akhir episode ini, kamu akan bisa menyusun element berdampingan memakai dua alat: flexbox untuk menjajarkan isi dalam satu arah, dan grid untuk membagi ruang menjadi kolom-kolom yang rapi.

Kamu akan mengenal property display, pintu masuk ke kedua alat itu, ditambah tiga kawan flexbox yang paling sering dipakai: justify-content, align-items, dan gap.

Kamu juga akan berkenalan dengan element <div>, kotak netral tanpa makna, lengkap dengan aturan kapan ia boleh dipakai dan kapan sebaiknya tidak.

Praktiknya dua: header halaman profil belajarmu menjadi navbar satu baris, dan dua kartu section berdiri berdampingan sebagai galeri kecil.

Kita belum membahas cara layout menyesuaikan diri dengan layar sempit. Halaman hari ini kita tata untuk layar lebar dulu; membuatnya luwes di semua ukuran layar adalah cerita utuh Episode 2.05.

Property display: Mengubah Cara Kotak Berperilaku

Setiap element punya cara bawaan menempati ruang. <p>, <section>, dan kawan-kawannya mengambil satu baris penuh, itulah kenapa semuanya tersusun menurun. Sementara <a> dan <img> mengalir di dalam baris teks.

Property display mengubah perilaku itu. Dua value-nya yang kita pelajari hari ini bukan mengatur element itu sendiri, melainkan mengatur anak-anak di dalamnya:

display: flex;
display: grid;

Keduanya dipasang di element induk, lalu induknya berubah menjadi wadah penata: semua anak langsungnya ikut aturan tata letak si induk. Kalimat ini layak dibaca dua kali, karena kesalahan paling umum di bab ini adalah memasang display: flex di anak yang ingin dijajarkan, bukan di induknya.

Flexbox: Menjajarkan Isi dalam Satu Arah

Flexbox adalah alat penata satu arah: ia menyusun anak-anak sebuah element dalam satu baris (atau satu kolom), lalu memberi kita kendali atas jarak dan perataannya.

Sasaran pertama kita adalah header. Sejak Episode 1.04, isinya dua anak: paragraf nama situs dan <nav>. Selama ini mereka bertumpuk. Kita ingin pola navbar klasik: nama di kiri, menu di kanan, sejajar rapi di tengah secara vertikal.

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Tiga property itu bekerja seperti ini. display: flex mengubah header menjadi wadah flex, sehingga dua anaknya berdiri satu baris. justify-content: space-between mengatur pembagian ruang di sepanjang baris: anak pertama menempel ke kiri, anak terakhir ke kanan, sisa ruangnya di tengah. Dan align-items: center meratakan anak-anak pada arah silangnya, sehingga nama situs dan menu sama-sama duduk di tengah tinggi header.

Satu lagi kawan flexbox yang wajib kenal: gap, jarak antaranak. Kita pasang di <nav> supaya dua link navigasinya tidak berdempetan:

nav {
  display: flex;
  gap: 16px;
}

Perhatikan polanya lagi: gap juga ditulis di induk, dan berlaku untuk jarak antaranak-anaknya. Sebelum ada gap, jarak antar-item dulu diakali dengan margin kiri-kanan yang sering tidak rapi; sekarang cukup satu property di satu tempat.

Tamu yang Ditunggu: Element div

Sekarang kartu-kartunya. Dua <section> kita ingin berdiri berdampingan. Mengikuti pola tadi, aturan tata letaknya harus dipasang di element induk yang membungkus keduanya.

Tetapi induk langsung mereka adalah <article>, dan <article> juga berisi judul, paragraf, dan foto. Kalau <article> kita jadikan wadah penata, semua isinya ikut ditata, padahal kita hanya ingin menata dua kartu itu. Kita butuh satu kotak baru yang tugasnya cuma satu: membungkus dua kartu.

Kotak apa yang cocok? Mari periksa lemari element kita. <section> berarti kelompok tematik ber-heading. <header>, <footer>, <nav>, <main>, <article>, semuanya punya makna. Sementara kotak yang kita butuhkan tidak punya makna apa-apa; ia murni keperluan tata letak.

Untuk itulah HTML menyediakan <div>: element kotak yang tidak berarti apa-apa. Browser dan alat bantu baca tidak menganggapnya bagian bermakna; ia sekadar pengelompokan netral.

Mungkin kamu bertanya: kalau senetral itu, kenapa baru diperkenalkan sekarang? Justru karena itu. <div> bisa dipakai untuk segalanya, sehingga di banyak tutorial ia dipakai untuk segalanya, dan halamannya kehilangan makna. Kamu sudah terbiasa memilih element yang bermakna lebih dulu; itu kebiasaan yang mahal harganya dan tidak boleh hilang. Aturannya sederhana: pakai <div> hanya jika tidak ada element semantic yang cocok. Ia pilihan terakhir, bukan pilihan pertama.

Untuk kasus kita hari ini, "baris berisi dua kartu" memang tidak punya element bermakna. Ini pekerjaan yang tepat untuk <div>:

<div class="galeri-kartu">
  <section class="kartu-utama">
    ...
  </section>
  <section>
    ...
  </section>
</div>

Sebagai catatan kecil: <div> punya saudara bernama <span>, versi sebaris yang membungkus potongan teks tanpa makna. Prinsipnya sama, dipakai belakangan saat benar-benar dibutuhkan.

Grid Ringan: Membagi Ruang Menjadi Kolom

Untuk menata isi galeri-kartu, kita pakai alat kedua: grid. Kalau flexbox berpikir "jajarkan isi dalam satu arah", grid berpikir "bagi ruangnya menjadi kolom (dan baris), lalu isi menempati kolom itu".

.galeri-kartu {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 16px;
}

Property grid-template-columns mendefinisikan kolom-kolomnya. Di sini ada satuan baru yang khusus milik grid: fr, singkatan dari fraction, bagian dari ruang yang tersedia. 1fr 1fr artinya dua kolom yang masing-masing kebagian satu bagian sama besar. Dua kartu kita otomatis sama lebar, tanpa menghitung piksel sama sekali.

gap yang kamu kenal dari flexbox bekerja di grid juga, memberi jarak antarkolom. Karena jarak antarkartu sekarang diurus gap, sebentar lagi di praktik kita akan memindahkan margin-top dari aturan section ke galeri, supaya tidak ada jarak yang dihitung dua kali.

Lalu kapan pakai flexbox, kapan grid? Patokan awal yang cukup untuk seri ini: flexbox untuk menjajarkan isi yang ukurannya boleh berbeda-beda dalam satu arah, seperti navbar; grid untuk membagi ruang menjadi kolom-kolom yang tegas dan sama rapi, seperti galeri kartu. Keduanya sering hidup berdampingan di satu halaman, seperti hari ini.

Preview Singkat: Layout Konten dan Sidebar

Satu pola lagi layak dilihat sekilas, walau belum kita praktikkan: halaman dua kolom, konten utama di kiri dan kolom samping (sidebar) yang lebih sempit di kanan. Banyak blog memakainya untuk daftar kategori atau tautan populer.

Dengan grid, polanya cuma soal perbandingan kolom:

.tata-letak {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 16px;
}

2fr 1fr artinya ruang dibagi tiga bagian: konten mendapat dua, sidebar mendapat satu. Halaman profil kita belum butuh sidebar, jadi simpan pola ini di saku dulu; ia akan berguna saat blog kita tumbuh.

Praktik Kecil: Navbar dan Galeri Kartu

Waktunya praktik. Ada dua file yang disentuh hari ini, index.html dan style.css.

Langkah pertama, di index.html: bungkus dua <section> kartu dengan <div class="galeri-kartu">. Tag pembukanya diletakkan sebelum section pertama, tag penutupnya setelah section kedua, seperti contoh di bagian <div> tadi. Struktur lain tidak berubah.

Langkah kedua, di style.css: ubah aturan header dan section, lalu tambahkan aturan nav dan .galeri-kartu, sehingga keempatnya menjadi seperti ini:

header {
  background-color: #e8eef5;
  padding: 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

nav {
  display: flex;
  gap: 16px;
}

section {
  background-color: #ffffff;
  border: 1px solid #d9d9d9;
  padding: 16px;
}

.galeri-kartu {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 16px;
}

Perhatikan section: margin-top: 16px yang dulu ada di sana sekarang pindah ke .galeri-kartu. Jarak antarkartu kini diurus gap, jarak galeri ke elemen di atasnya diurus margin-top galeri. Satu jarak, satu pengurus.

Simpan keduanya, lalu refresh. Header berubah menjadi navbar sungguhan: nama situs di kiri, dua link menu rapi di kanan. Di bawah, dua kartu yang dulu bertumpuk kini berdiri berdampingan, sama lebar, dengan jarak yang rapi.

Kalau semua langkah tadi benar, halamanmu kurang lebih akan tampil seperti ini:

Hasil yang diharapkan

Dua kartunya sekarang bertetangga, dan navbar-nya terasa seperti navbar blog sungguhan. Foto profil masih kotak abu-abu pengganti, dan tinggi kedua kartu boleh berbeda sedikit tergantung isinya; itu wajar.

Sebelum lanjut, mainkan dulu: ganti grid-template-columns menjadi 1fr 1fr 1fr dan lihat kartu-kartunya menyempit menyisakan kolom kosong, coba 2fr 1fr dan lihat kartu pertama melebar, lalu kembalikan ke 1fr 1fr. Ubah juga gap menjadi 32px untuk merasakan jaraknya. Alat baru paling cepat akrab lewat tangan.

Urutan Visual dan Urutan Baca

Satu pesan aksesibilitas sebelum menutup. Flexbox dan grid mengubah posisi visual element, tetapi pembaca layar dan tombol Tab tetap mengikuti urutan penulisan di HTML.

Hari ini keduanya masih sejalan: kartu Rujukan ditulis lebih dulu dan tampil di kiri. Jaga terus keselarasan itu. Kalau suatu hari kamu ingin mengubah urutan tampilan, ubahlah urutan elementnya di HTML, bukan mengakalinya lewat CSS. Halaman yang urutan bacanya melompat-lompat membingungkan pengguna keyboard, walau terlihat rapi di mata.

Kesalahan Umum Pemula

Kesalahan pertama, sekaligus yang paling klasik: memasang display: flex atau display: grid di element yang ingin dijajarkan, bukan di induknya. Kalau tata letakmu tidak berubah sama sekali, cek dulu di mana aturannya menempel. Wadahnya yang diberi aturan, bukan isinya.

Kesalahan kedua: gap ditulis di element yang bukan wadah flex atau grid. gap hanya bekerja di dalam wadah penata; di element biasa ia diabaikan diam-diam.

Kesalahan ketiga: begitu kenal <div>, semua dibungkus <div>. Header pakai div, daftar pakai div, artikel pakai div. Halamanmu kembali menjadi tumpukan kotak tanpa makna, dan kerja keras Session 1 sia-sia. Urutan berpikirnya tetap: element semantic dulu, <div> hanya kalau tidak ada yang cocok.

Kesalahan keempat: lupa menutup </div>. Karena div tidak terlihat, tag penutup yang hilang sering tidak disadari, dan tiba-tiba aturan CSS menata lebih banyak element daripada seharusnya. Kalau tata letak terasa "menjalar" ke bagian yang bukan sasaran, hitung pembuka dan penutup div-mu.

Kesalahan kelima: jarak ganda karena margin lama dibiarkan saat gap sudah dipasang. Gejalanya jarak antarkartu lebih lebar dari yang diminta. Kita sudah mencegahnya hari ini dengan memindahkan margin-top dari section ke galeri; ingat prinsipnya, satu jarak satu pengurus.

Rangkuman

Layout adalah urusan meletakkan kotak-kotak, dan pintu masuknya property display yang dipasang di element induk. Flexbox (display: flex) menjajarkan anak-anak dalam satu arah, dengan justify-content untuk pembagian ruang, align-items untuk perataan silang, dan gap untuk jarak antaranak. Grid (display: grid) membagi ruang menjadi kolom lewat grid-template-columns, dengan satuan fr sebagai bagian ruang yang tersedia.

Kamu juga resmi berkenalan dengan <div>, kotak netral tanpa makna, berikut aturan mainnya: element semantic dulu, <div> pilihan terakhir. Penantiannya sejak Session 1 memang disengaja, supaya aturan itu tertanam sebelum godaannya datang.

Halaman profil belajarmu kini punya navbar satu baris dan galeri dua kartu yang berdampingan. Dari tumpukan buku menjadi halaman yang tertata dua dimensi; itu lompatan yang pantas dirayakan.

Berikutnya

Ada satu ujian yang belum dihadapi halaman kita: layar kecil. Coba sempitkan jendela browsermu perlahan; dua kartu itu mulai berdesakan, dan navbar kita mulai sesak. Padahal sebagian besar pembaca blog datang dari ponsel.

Di Episode 2.05, penutup Session 2, kita membuat layout hari ini luwes di semua ukuran layar: berkenalan dengan media query, breakpoint, dan cara berpikir mobile-first. Halaman yang sama, nyaman di ponsel maupun monitor lebar.

Belajar Lebih Lanjut

Kalau ingin belajar lebih lanjut, kamu juga bisa membaca beberapa rujukan berikut.