Subbab 3 / 9

SI ES ES🥶

Materi : CSS (Cascading Style Sheets)

Topik : Selector, Cascade, Box Model, Typography, Positioning, Flexbox, Grid, Media Query, Responsive Design


1. Pendahuluan: Apa itu CSS dan Kenapa Kita Butuh CSS?

HTML bertugas membangun struktur dan konten halaman (heading, paragraf, gambar, tombol, dll). Tapi HTML sendiri tidak tahu bagaimana elemen-elemen itu harus terlihat.

Coba bayangkan tanpa CSS : semua halaman web di dunia ini akan terlihat seperti dokumen teks polos font default, warna hitam-putih, semua elemen tersusun dari atas ke bawah tanpa tata letak. CSS (Cascading Style Sheets) adalah bahasa yang memberi "wajah" pada struktur HTML tersebut: warna, jarak, ukuran, posisi, animasi, hingga tata letak responsif di berbagai ukuran layar.


Analogi sederhana :

  • HTML = kerangka rumah (dinding, pintu, jendela)
  • CSS = interior desain (cat, lantai, furniture, pencahayaan)


Cara Menghubungkan CSS ke HTML

Ada 3 cara, tapi hanya 1 yang jadi best practice :

Cara

Contoh

Kapan dipakai

Inline

<p style="color:red;">Teks</p>

Hindari — susah dikelola, spesifisitas tinggi

Internal

<style> p { color:red; } </style> di <head>

Untuk contoh cepat / prototipe kecil

External (disarankan)

<link rel="stylesheet" href="style.css">

Untuk proyek nyata — bisa dipakai ulang di banyak halaman, gampang di-maintain

Kenapa external lebih disarankan? Karena memisahkan concern (struktur vs tampilan), file bisa di-cache browser (loading lebih cepat di kunjungan berikutnya), dan satu file CSS bisa dipakai di puluhan halaman HTML sekaligus.


2. Selector CSS

Selector adalah "penunjuk" atau cara kita memilih elemen HTML mana yang ingin diberi style.


2.1 Selector Dasar

css
1
2
3
4
5
6
7
8
9
10
11
/* Element selector — pilih semua tag <p> */
p { color: navy; }

/* Class selector — pilih elemen dengan class="highlight" */
.highlight { background-color: yellow; }

/* ID selector — pilih elemen dengan id="header" (harus unik di 1 halaman) */
#header { font-size: 24px; }

/* Universal selector — pilih SEMUA elemen */
* { box-sizing: border-box; }

Kapan pakai class vs id?

  • class → dipakai berkali-kali, untuk styling yang reusable (misalnya semua tombol punya class .btn)
  • id → hanya boleh 1 kali per halaman, biasanya dipakai untuk target JavaScript atau anchor link, bukan untuk styling utama karena spesifisitasnya terlalu tinggi dan sulit di-override


2.2 Selector Kombinasi

css
1
2
3
4
5
6
7
8
9
10
11
/* Descendant — semua <a> di dalam <nav>, sejauh apapun turunannya */
nav a { text-decoration: none; }

/* Child — hanya <li> yang LANGSUNG anak dari <ul> */
ul > li { list-style: none; }

/* Adjacent sibling — <p> yang persis setelah <h2> */
h2 + p { font-weight: bold; }

/* General sibling — semua <p> setelah <h2> (di level sama) */
h2 ~ p { color: gray; }

Kenapa penting membedakan nav a dan nav > a? Kalau struktur HTML-mu bersarang dalam (misalnya <nav><ul><li><a>), nav > a tidak akan mengenai <a> tersebut karena bukan anak langsung. Salah pilih combinator = style tidak muncul, dan ini salah satu bug paling umum pemula.


2.3 Pseudo-class dan Pseudo-element

css
1
2
3
4
5
6
7
8
9
/* Pseudo-class — kondisi/state elemen */
a:hover { color: red; }
input:focus { border-color: blue; }
li:first-child { font-weight: bold; }
li:nth-child(2n) { background: #f0f0f0; } /* zebra striping */

/* Pseudo-element — bagian tertentu dari elemen */
p::first-letter { font-size: 200%; }
p::before { content: "→ "; }

Jika tidak menggunakan pseudo-class, kamu terpaksa menambahkan/menghapus class lewat JavaScript hanya untuk efek hover atau styling baris genap-ganjil pada tabel padahal browser sudah menyediakan mekanisme bawaan yang lebih ringan dan tanpa JavaScript sama sekali.


2.4 Attribute Selector

css
1
2
input[type="text"] { border: 1px solid gray; }
a[target="_blank"] { color: orange; }

Berguna saat elemen tidak punya class tapi bisa dibedakan dari atributnya, misalnya membedakan <input type="text"> dan <input type="checkbox"> tanpa menambah class manual di HTML.


3. Cascade & Specificity (Kenapa CSS Kadang "Tidak Ngaruh"?)

Ini adalah bagian yang paling sering membingungkan pemula: kenapa style yang saya tulis tidak muncul, padahal tidak ada error?

Jawabannya ada pada 3 konsep: Cascade, Specificity, dan Source Order.


3.1 Cascade (Urutan Prioritas)

Ketika ada beberapa aturan yang bentrok pada elemen yang sama, browser menentukan pemenang berdasarkan urutan:

  1. Importance - !important menang di atas segalanya (tapi sebaiknya dihindari)
  2. Specificity - selector yang lebih spesifik menang
  3. Source order - kalau specificity sama, aturan yang ditulis paling akhir yang menang


3.2 Specificity (Bobot Selector)

Setiap selector punya "skor". Semakin spesifik, semakin tinggi skornya:

Selector

Skor (id, class, element)

Contoh

Element

0-0-1

p

Class / attribute / pseudo-class

0-1-0

.btn, :hover

ID

1-0-0

#header

Inline style

tertinggi

style="..."

css
1
2
3
p { color: blue; }              /* skor 0-0-1 */
.text { color: green; }         /* skor 0-1-0 → menang */
#main p.text { color: red; }    /* skor 1-1-1 → menang di atas semuanya */

Kenapa harus paham ini? Kalau tidak paham cascade, pemula biasanya akan "menyerah" dan menyelesaikan masalah dengan menambahkan !important di mana-mana. Ini anti-pattern: begitu satu !important dipakai, style lain butuh !important juga untuk override, dan akhirnya CSS jadi tidak terkontrol dan sangat sulit di-maintain. Memahami specificity artinya kamu bisa menulis selector yang "cukup spesifik" tanpa perlu senjata pamungkas itu.


4. Box Model

Setiap elemen HTML pada dasarnya adalah sebuah kotak (box), tersusun dari 4 lapisan:

css
1
2
3
4
5
6
.box {
  width: 300px;
  padding: 20px;
  border: 5px solid black;
  margin: 10px;
}

4.1 Masalah Klasik : content-box vs border-box

Secara default, width di CSS hanya mengatur content, bukan total lebar kotak. Ini sering bikin bingung:

css
1
2
3
4
5
6
.box {
  width: 300px;
  padding: 20px;
  border: 5px solid black;
  /* Lebar total sebenarnya = 300 + 20+20 (padding) + 5+5 (border) = 350px! */
}

Pemula sering berencana membuat 3 kolom @300px pas 1 baris (900px), tapi ternyata meleber jadi 1050px dan malah turun ke baris baru inilah akibat tidak paham box model.


Solusi standar industri:

css
1
2
3
* {
  box-sizing: border-box;
}

Dengan border-box, width: 300px sudah termasuk padding dan border di dalamnya — jadi lebar total kotak pasti 300px. Inilah alasan hampir semua CSS reset/framework modern (Bootstrap, Tailwind) langsung set box-sizing: border-box di awal.


4.2 Margin Collapsing

Satu perilaku "aneh" yang wajib diketahui: margin vertikal antar elemen sibling tidak dijumlahkan, melainkan diambil yang terbesar.

css
1
2
3
.a { margin-bottom: 30px; }
.b { margin-top: 20px; }
/* Jarak antara .a dan .b BUKAN 50px, tapi 30px (nilai terbesar) */

Ini sering membuat pemula bingung kenapa jarak antar elemen "tidak nambah" walau margin sudah ditambah dua-duanya.


5. Typography

Typography menentukan keterbacaan dan kenyamanan visual teks di halaman.

css
1
2
3
4
5
6
7
8
body {
  font-family: "Segoe UI", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
  letter-spacing: 0.5px;
  text-align: left;
}

5.1 Kenapa Selalu Sediakan Font Fallback?

font-family: "Segoe UI", Arial, sans-serif; daftar ini adalah urutan prioritas. Jika font pertama tidak tersedia di device pengguna (misalnya user pakai Linux/HP tanpa font tersebut ter-install), browser otomatis pindah ke font berikutnya. Jika tidak diberi fallback, dan font utama gagal dimuat, browser akan menggunakan font default yang tidak konsisten antar device.


5.2 Satuan Ukuran: px vs em vs rem

Satuan

Sifat

Kapan dipakai

px

Absolut, tetap

Border, shadow, elemen kecil yang tidak perlu scaling

em

Relatif ke font-size parent

terdekat Bisa "menumpuk" (compounding) — hati-hati

rem

Relatif ke font-size root (html)

Disarankan untuk font-size, spacing, agar konsisten dan mudah diskalakan

Kenapa rem lebih disukai daripada px untuk font? Karena rem menghormati pengaturan aksesibilitas browser pengguna (misalnya user memperbesar font default browser untuk kenyamanan mata). Kalau kamu memaksa px, ukuran teks di layar user akan tetap kaku sebesar itu mengabaikan preferensi aksesibilitas mereka. rem juga membuat perubahan skala global jadi mudah: cukup ubah font-size di html, seluruh elemen yang pakai rem ikut menyesuaikan proporsional.


Kenapa em bisa berbahaya? Karena bersifat relatif ke parent, jika elemen bersarang dalam (nested), ukurannya bisa "membengkak" tanpa disadari:

css
1
2
3
.parent { font-size: 20px; }
.child { font-size: 1.5em; }       /* = 30px */
.grandchild { font-size: 1.5em; }  /* = 45px, bukan 30px! karena relatif ke .child */

6. Positioning

Property position menentukan bagaimana elemen ditempatkan relatif terhadap elemen lain.

css
1
2
3
4
5
.static    { position: static; }    /* default — mengikuti alur normal dokumen */
.relative  { position: relative; top: 10px; left: 10px; }
.absolute  { position: absolute; top: 0; right: 0; }
.fixed     { position: fixed; bottom: 20px; right: 20px; }
.sticky    { position: sticky; top: 0; }

Nilai

Perilaku

Contoh Penggunaan

static

Default, tidak bisa diatur top/left/right/bottom

Elemen biasa

relative

Bergeser dari posisi aslinya, tapi tetap "menyisakan ruang" di layout asal

Membuat elemen jadi referensi untuk child absolute

absolute

Keluar dari alur dokumen, posisi mengikuti ancestor terdekat yang position-nya bukan static

Badge notifikasi, dropdown menu, tooltip

fixed

Posisi tetap relatif ke viewport, tidak ikut scroll

Tombol "back to top", navbar melayang

sticky

Bertingkah seperti relative sampai titik scroll tertentu, lalu "menempel" seperti fixed

Header tabel, navbar yang menempel saat discroll

6.1 Konsep Kunci: "Positioning Context"

absolute selalu mencari ancestor terdekat yang punya position selain static sebagai acuan. Kalau tidak ketemu, acuannya adalah <html> (viewport dokumen).

css
1
2
3
4
5
6
7
8
.card {
  position: relative;   /* jadi "acuan" untuk child absolute */
}
.badge {
  position: absolute;
  top: 5px;
  right: 5px;            /* akan menempel di pojok kanan-atas .card, bukan halaman */
}

Jika .card tidak diberi position: relative, maka .badge akan mencari ancestor lain di atasnya bisa jadi melompat ke pojok kanan atas seluruh halaman, bukan pojok kartu. Ini salah satu bug positioning paling umum: lupa memberi position: relative pada parent.


7. Flexbox

Flexbox dirancang untuk mengatur elemen dalam satu dimensi baris (row) atau kolom (column).

css
1
2
3
4
5
6
7
8
9
10
11
12
.container {
  display: flex;
  flex-direction: row;        /* row | column */
  justify-content: center;    /* pengaturan sumbu utama (horizontal jika row) */
  align-items: center;        /* pengaturan sumbu silang (vertikal jika row) */
  gap: 16px;
  flex-wrap: wrap;
}

.item {
  flex: 1;    /* elemen tumbuh mengisi ruang tersedia secara proporsional */
}

7.1 Kenapa Flexbox Ada? (Masalah Sebelum Flexbox)

Sebelum Flexbox populer (sekitar 2015-an), developer membuat layout dengan float atau display: inline-block, yang punya banyak masalah:

  • Elemen float keluar dari alur normal, sehingga parent-nya bisa "collapse" (tinggi jadi 0) perlu trik clearfix
  • Centering vertikal itu sangat sulit tanpa Flexbox (butuh trik position + transform, atau tabel)


Dengan Flexbox, centering elemen secara vertikal & horizontal cukup:

css
1
2
3
4
5
.center {
  display: flex;
  justify-content: center;
  align-items: center;
}

Jika tidak menggunakan Flexbox untuk kasus seperti navbar (logo di kiri, menu di kanan, sejajar vertikal), kamu harus menghitung posisi manual dengan position: absolute dan margin, yang rapuh terhadap perubahan ukuran konten.


7.2 Properti Kunci

Pada container (parent):

  • justify-content - mengatur sumbu utama (main axis)
  • align-items - mengatur sumbu silang (cross axis)
  • flex-wrap - apakah item boleh pindah baris jika ruang tidak cukup

Pada item (child):

  • flex-grow - seberapa besar item "menyerap" ruang kosong
  • flex-shrink - seberapa besar item boleh menyusut
  • flex-basis - ukuran awal sebelum grow/shrink dihitung



8. CSS Grid

Grid dirancang untuk mengatur elemen dalam dua dimensi sekaligus baris dan kolom.

css
1
2
3
4
5
6
7
8
9
10
11
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 3 kolom sama lebar */
  grid-template-rows: auto 200px auto;
  gap: 20px;
}

.item-hero {
  grid-column: 1 / 3;   /* elemen ini melebar 2 kolom */
  grid-row: 1 / 2;
}

8.1 Kenapa Grid Dibutuhkan Kalau Sudah Ada Flexbox?

Flexbox itu satu dimensi kalau kamu punya banyak baris, setiap baris "tidak tahu-menahu" ukuran kolom di baris lain, sehingga kolom antar baris tidak otomatis sejajar kecuali diatur manual dengan trik tambahan.


Coba bayangkan membuat layout galeri foto atau dashboard dengan banyak baris & kolom yang harus sejajar rapi dengan Flexbox kamu harus membungkus banyak div bersarang dan menghitung lebar manual. Dengan Grid, cukup definisikan struktur kolom & baris sekali di parent, lalu setiap item otomatis menempati sel gridnya, bahkan bisa melintasi beberapa kolom/baris sekaligus (grid-column: span 2).


Grid juga mendukung template area yang sangat deskriptif:

css
1
2
3
4
5
6
7
8
9
10
11
12
.layout {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
  grid-template-columns: 200px 1fr;
}
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer  { grid-area: footer; }

Bandingkan dengan cara lama (float/table layout) yang butuh markup HTML tambahan hanya demi keperluan visual Grid memisahkan struktur visual dari struktur HTML, sehingga HTML tetap semantik.


8.2 Flexbox vs Grid: Kapan Pakai yang Mana?

Ini pertanyaan yang sering ditanyakan oleh pemula:

Aspek

Flexbox

Grid

Dimensi

1 dimensi (baris atau kolom)

2 dimensi (baris dan kolom sekaligus)

Cocok untuk

Navbar, tombol sejajar, daftar item, centering

Layout halaman keseluruhan, dashboard, galeri foto

Kontrol ukuran

Item menyesuaikan konten (content-first)

Kolom/baris didefinisikan dulu, item mengikuti (layout-first)

Sifat

Elemen bisa "mengalir" fleksibel

Struktur grid lebih kaku & presisi

Aturan praktis: Kalau kamu berpikir "saya ingin mengatur baris ATAU kolom" - Flexbox. Kalau kamu berpikir "saya ingin mengatur baris DAN kolom sekaligus, dan ingin semuanya sejajar rapi" - Grid. Faktanya, dalam proyek nyata, keduanya sering dipakai bersamaan: Grid untuk struktur besar halaman (header, sidebar, content, footer), dan Flexbox untuk menyusun elemen-elemen kecil di dalam masing-masing bagian tersebut (misalnya isi navbar).


9. Media Query & Responsive Design

Responsive design adalah pendekatan membuat 1 halaman web yang tampilannya menyesuaikan diri di berbagai ukuran layar - dari HP, tablet, hingga desktop - tanpa perlu membuat halaman terpisah untuk tiap device.


9.1 Kenapa Responsive Design Wajib?

Bayangkan tanpa responsive design: layout 3 kolom yang didesain untuk layar desktop 1200px, dibuka di HP dengan layar 375px. Kolom-kolom itu akan "diperas" jadi sangat sempit, teks jadi tidak terbaca, atau malah muncul scrollbar horizontal yang mengharuskan user menggeser layar ke samping - pengalaman yang sangat buruk. Mengingat mayoritas trafik web saat ini datang dari perangkat mobile, mengabaikan responsive design berarti mengabaikan sebagian besar calon pengguna.


9.2 Media Query

css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Style default untuk mobile (mobile-first) */
.container {
  display: flex;
  flex-direction: column;
}

/* Saat layar minimal 768px (tablet ke atas) */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}

/* Saat layar minimal 1024px (desktop) */
@media (min-width: 1024px) {
  .container {
    max-width: 1200px;
    margin: 0 auto;
  }
}

9.3 Mobile-First vs Desktop-First

Pendekatan

Cara kerja

Kelebihan

Mobile-first (disarankan)

Style dasar untuk mobile, lalu min-width menambah kompleksitas untuk layar besar

CSS lebih ringan di HP (device dengan resource paling terbatas dilayani duluan), memaksa developer fokus konten prioritas

Desktop-first

Style dasar untuk desktop, lalu max-width menyederhanakan untuk layar kecil

Lebih intuitif jika desain awal dibuat untuk desktop, tapi sering menghasilkan CSS override yang lebih rumit

Kenapa mobile-first jadi standar industri saat ini? Karena lebih mudah "menambahkan" kompleksitas seiring bertambah lebarnya layar, dibanding "membongkar" layout kompleks jadi sederhana. Selain itu, browser mobile akan mengunduh & memproses CSS lebih sedikit karena style tambahan hanya dimuat saat kondisi min-width terpenuhi.


9.4 Breakpoint Umum (Acuan, Bukan Aturan Mutlak)

css
1
2
3
4
5
6
7
8
9
/* Extra small (HP) - default, tanpa media query */
/* Small (tablet portrait) */
@media (min-width: 576px)  { }
/* Medium (tablet landscape) */
@media (min-width: 768px)  { }
/* Large (laptop) */
@media (min-width: 992px)  { }
/* Extra large (desktop) */
@media (min-width: 1200px) { }

Catatan penting: breakpoint sebaiknya ditentukan berdasarkan di titik mana layout mulai "rusak" (konten berantakan / terlalu renggang), bukan berdasarkan ukuran device tertentu karena ukuran layar device di pasaran sangat beragam dan terus berubah.


9.5 Unit Responsif Tambahan

Selain media query, elemen berikut membantu membuat layout otomatis fleksibel tanpa banyak breakpoint:

css
1
2
3
4
5
6
7
img { max-width: 100%; height: auto; }  /* gambar tidak akan melebihi lebar container */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  /* kolom otomatis menyesuaikan jumlah sesuai lebar layar, tanpa perlu media query! */
}

Kenapa ini penting ditekankan? Pemula sering berpikir "responsive = banyak media query". Padahal, kombinasi Flexbox/Grid dengan unit fleksibel (fr, %, minmax(), auto-fit) bisa membuat layout responsif secara alami dengan jauh lebih sedikit kode media query.


10. Rangkuman

Konsep

Fungsi Utama

Analogi

Selector

Menunjuk elemen mana yang di-style

Alamat rumah

Cascade & Specificity

Menentukan aturan mana yang menang saat bentrok

Hierarki komando

Box Model

Struktur ruang tiap elemen

Kotak berlapis (isi, bantalan, bingkai, jarak)

Typography

Keterbacaan & estetika teks

Tata letak huruf di buku

Positioning

Menempatkan elemen di luar alur normal

Menempel stiker di posisi tertentu

Flexbox

Layout 1 dimensi

Barisan orang mengantre

Grid

Layout 2 dimensi

Papan catur

Media Query

Adaptasi tampilan sesuai layar

Baju yang menyesuaikan ukuran badan