kodingup.camp

Beranda/HTML, CSS & SCSS Mastery

Arsitektur Layout Fleksibel

Modul 7 dari 115 menit bacaFlexible Layout Architecture

Isi modul

    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:

    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:

    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.

    Menempatkan item:

    .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

    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">&copy; 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

    1. Memasang justify-content pada item, bukan container. Cara benar: properti perataan utama dipasang di elemen yang punya display: flex/grid.
    2. Bingung sumbu saat flex-direction: column. Di mode kolom, justify-content mengatur vertikal dan align-items mengatur horizontal. Cara benar: ingat bahwa justify selalu mengikuti main axis.
    3. Memakai margin untuk jarak antar item. Cara benar: pakai gap, yang tidak menambah jarak di tepi luar.
    4. Teks panjang membuat flex item meluber. Penyebabnya min-width: auto bawaan flex item. Cara benar: beri min-width: 0 pada item yang berisi teks panjang.
    5. grid-template-areas dengan jumlah kolom tidak konsisten atau area berbentuk L. Cara benar: setiap string sama panjang kolomnya dan setiap area berbentuk persegi panjang.

    Latihan

    1. Mudah, Taruh sebuah kotak tepat di tengah layar (horizontal dan vertikal) dengan dua cara: Flexbox dan Grid.
    2. Sedang, Buat galeri foto responsif yang minimal 180px per kolom dan otomatis menyesuaikan jumlah kolom, dengan jarak 12px.
    3. 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

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.