Skip to content

harryrosianto/CSS_101_AIDA

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

Daftar Isi

  1. Apa itu CSS?
  2. Cara Menyisipkan CSS
  3. Selektor CSS
  4. Spesifisitas dan Cascade
  5. Box Model
  6. Satuan Ukuran (Units)
  7. Warna
  8. Tipografi
  9. Background
  10. Border
  11. Display dan Visibility
  12. Positioning
  13. Float dan Clear
  14. Flexbox
  15. CSS Grid
  16. Overflow
  17. Transformasi (Transform)
  18. Transisi (Transition)
  19. Animasi (Animation)
  20. CSS Custom Properties (Variabel CSS)
  21. Pseudo-class
  22. Pseudo-element
  23. Media Query dan Responsive Design
  24. Filter dan Efek Visual
  25. CSS Functions
  26. Z-index dan Stacking Context
  27. Outline, Shadow, dan Efek Lainnya
  28. Cursor dan Pointer Events
  29. Scroll Behavior
  30. Best Practice dan Metodologi CSS

1. Apa itu CSS?

CSS (Cascading Style Sheets) adalah bahasa yang digunakan untuk mendeskripsikan tampilan dan format dokumen yang ditulis dalam HTML. CSS mengontrol bagaimana elemen HTML ditampilkan di layar, kertas, atau media lainnya.

Tiga pilar web:

Bahasa Fungsi
HTML Struktur dan konten
CSS Tampilan dan gaya visual
JavaScript Perilaku dan interaktivitas

Mengapa disebut "Cascading"?

Karena aturan gaya mengalir (cascade) dari sumber yang berbeda dan diterapkan dengan urutan prioritas tertentu. Jika ada dua aturan yang bertentangan untuk elemen yang sama, CSS menentukan mana yang menang berdasarkan spesifisitas, urutan kemunculan, dan sumber aturan tersebut.

Cara kerja CSS:

Browser membaca HTML dan CSS, lalu membangun dua pohon internal: DOM (Document Object Model) untuk HTML dan CSSOM (CSS Object Model) untuk CSS. Keduanya digabungkan menjadi Render Tree, yang kemudian digunakan untuk menghitung tata letak dan menggambar piksel di layar.


2. Cara Menyisipkan CSS

2.1 External Stylesheet (Disarankan)

File CSS terpisah, dihubungkan melalui tag <link> di <head>.

<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8">
  <title>Halaman Saya</title>

  <!-- rel="stylesheet" memberitahu browser bahwa ini adalah file CSS -->
  <!-- href berisi path ke file CSS, bisa relatif atau absolut -->
  <link rel="stylesheet" href="styles/main.css">

  <!-- Bisa menghubungkan banyak file CSS -->
  <link rel="stylesheet" href="styles/layout.css">
</head>
<body>
  <h1>Judul</h1>
</body>
</html>

Keuntungan: Dapat digunakan ulang di banyak halaman, browser melakukan caching sehingga halaman berikutnya dimuat lebih cepat, kode lebih terorganisir.

2.2 Internal Style (di dalam <style>)

<head>
  <style>
    /* CSS ditulis langsung di dalam tag style */
    /* Ini hanya berlaku untuk halaman ini saja */

    body {
      font-family: Georgia, serif;
      background-color: #f5f5f5;
    }

    h1 {
      color: navy;
      font-size: 2rem;
    }
  </style>
</head>

Kapan digunakan: Untuk halaman tunggal atau styling khusus yang hanya berlaku di satu halaman.

2.3 Inline Style

<!-- CSS langsung di atribut style elemen HTML -->
<!-- Memiliki prioritas tertinggi (kecuali !important) -->
<p style="color: red; font-size: 18px; margin: 0;">
  Paragraf dengan inline style.
</p>

Kapan digunakan: Sangat jarang, biasanya hanya dari JavaScript saat mengubah style secara dinamis.

2.4 Import CSS di dalam CSS

/* Di dalam file CSS, bisa mengimpor file CSS lain */
/* Harus diletakkan di baris paling atas */

@import url("reset.css");
@import url("typography.css");
@import url("components/button.css");

/* Setelah import, tulis CSS biasa */
body {
  margin: 0;
}

Catatan: @import sedikit lebih lambat dari <link> karena browser harus mengunduh file pertama sebelum menemukan import.


3. Selektor CSS

Selektor menentukan elemen HTML mana yang akan diberi gaya.

3.1 Selektor Dasar

/* Selektor Universal - memilih SEMUA elemen */
* {
  box-sizing: border-box; /* penggunaan paling umum */
  margin: 0;
  padding: 0;
}

/* Selektor Tipe/Elemen - memilih berdasarkan nama tag HTML */
h1 {
  font-size: 2rem;
}

p {
  line-height: 1.6;
}

/* Selektor Class - memilih elemen yang memiliki class tertentu */
/* Diawali dengan titik (.) */
.tombol {
  background-color: blue;
  color: white;
}

.tombol-besar {
  padding: 16px 32px;
  font-size: 1.2rem;
}

/* Selektor ID - memilih elemen dengan ID tertentu */
/* Diawali dengan tanda pagar (#) */
/* ID harus unik dalam satu halaman */
#header {
  background-color: #333;
  position: sticky;
  top: 0;
}

/* Selektor Atribut - memilih berdasarkan atribut HTML */
[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

[type="text"] {
  border: 1px solid #ccc;
}

[href^="https"] {
  /* href yang DIMULAI dengan "https" */
  color: green;
}

[href$=".pdf"] {
  /* href yang DIAKHIRI dengan ".pdf" */
  color: red;
}

[class*="icon"] {
  /* class yang MENGANDUNG kata "icon" */
  display: inline-block;
}

[lang|="id"] {
  /* nilai atribut yang tepat "id" atau diawali "id-" */
  font-family: 'Noto Sans', sans-serif;
}

[placeholder~="nama"] {
  /* nilai atribut yang mengandung kata "nama" (dipisah spasi) */
  border-color: purple;
}

3.2 Selektor Kombinasi

/* Descendant Combinator (spasi) */
/* Memilih .item yang merupakan KETURUNAN dari .container (di level mana saja) */
.container .item {
  color: blue;
}

/* Child Combinator (>) */
/* Memilih .item yang merupakan ANAK LANGSUNG dari .container */
.container > .item {
  font-weight: bold;
}

/* Adjacent Sibling Combinator (+) */
/* Memilih elemen p yang LANGSUNG SETELAH h2 (saudara langsung) */
h2 + p {
  margin-top: 0.5rem;
  font-style: italic;
}

/* General Sibling Combinator (~) */
/* Memilih SEMUA elemen p yang merupakan saudara setelah h2 */
h2 ~ p {
  color: #555;
}

3.3 Selektor Grup

/* Memilih beberapa elemen sekaligus, dipisah koma */
/* Berguna untuk menerapkan gaya yang sama ke banyak elemen */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: 'Georgia', serif;
  line-height: 1.2;
  color: #1a1a2e;
}

.tombol-primer,
.tombol-sekunder,
.tombol-bahaya {
  border: none;
  border-radius: 4px;
  cursor: pointer;
  padding: 8px 16px;
}

3.4 Selektor Gabungan (Chaining)

/* Elemen yang memiliki LEBIH DARI SATU kondisi sekaligus */
/* Tanpa spasi di antara selektor */

/* p yang juga memiliki class "penting" */
p.penting {
  font-weight: bold;
}

/* div yang memiliki class "kotak" DAN class "aktif" */
div.kotak.aktif {
  border: 2px solid blue;
}

/* input dengan type="email" dan atribut required */
input[type="email"][required] {
  border-color: red;
}

4. Spesifisitas dan Cascade

4.1 Cascade (Aturan Bertingkat)

Ketika ada aturan CSS yang bertentangan untuk elemen yang sama, browser menentukan mana yang digunakan berdasarkan urutan ini (dari tertinggi ke terendah):

  1. Deklarasi !important
  2. Inline style (style="...")
  3. ID selektor (#id)
  4. Class, pseudo-class, atribut (.class, :hover, [attr])
  5. Elemen dan pseudo-element (div, ::before)

4.2 Spesifisitas (Specificity)

Spesifisitas dihitung menggunakan sistem skor empat angka: (a, b, c, d)

Selektor a (inline) b (ID) c (class/pseudo/attr) d (elemen)
* 0 0 0 0
p 0 0 0 1
.kelas 0 0 1 0
#id 0 1 0 0
style="" 1 0 0 0
p.kelas 0 0 1 1
#id .kelas p 0 1 1 1
/* Contoh konflik spesifisitas */

/* Spesifisitas: (0,0,0,1) - kalah */
p {
  color: black;
}

/* Spesifisitas: (0,0,1,0) - menang dari selektor tipe */
.teks {
  color: blue;
}

/* Spesifisitas: (0,1,0,0) - menang dari class */
#konten {
  color: red;
}

/* !important - mengesampingkan semua perhitungan spesifisitas */
/* Gunakan sangat jarang, hanya jika benar-benar terpaksa */
p {
  color: green !important; /* ini akan selalu menang */
}

4.3 Inheritance (Pewarisan)

Beberapa properti CSS diwarisi oleh elemen anak secara otomatis, beberapa tidak.

/* Properti yang DIWARISI oleh default: */
/* color, font-family, font-size, font-weight, font-style,
   line-height, letter-spacing, text-align, text-transform,
   visibility, cursor, dan beberapa lainnya */

body {
  color: #333;         /* diwarisi oleh semua elemen di dalamnya */
  font-family: sans-serif; /* diwarisi */
}

/* Properti yang TIDAK diwarisi: */
/* margin, padding, border, background, width, height,
   display, position, dan sebagian besar properti layout */

/* Mengontrol inheritance secara eksplisit */
.anak {
  color: inherit;   /* paksa mewarisi dari induk */
  color: initial;   /* kembalikan ke nilai default browser */
  color: unset;     /* jika properti diwarisi: inherit; jika tidak: initial */
  color: revert;    /* kembalikan ke nilai default stylesheet browser */
}

5. Box Model

Setiap elemen HTML adalah sebuah kotak (box). Box Model menggambarkan bagaimana ukuran dan ruang elemen dihitung.

+------------------------------------------+
|                  margin                  |  <-- ruang di luar border (transparan)
|  +--------------------------------------+|
|  |               border                 ||  <-- garis batas elemen
|  |  +----------------------------------+||
|  |  |            padding               |||  <-- ruang di dalam border (mengambil background)
|  |  |  +----------------------------+  |||
|  |  |  |                            |  |||
|  |  |  |         content            |  |||  <-- area konten (teks, gambar, dll)
|  |  |  |                            |  |||
|  |  |  +----------------------------+  |||
|  |  +----------------------------------+||
|  +--------------------------------------+|
+------------------------------------------+

5.1 box-sizing

/* box-sizing menentukan apa yang dihitung sebagai "width" dan "height" */

/* Nilai DEFAULT: content-box */
/* width/height hanya menghitung area konten */
/* Total lebar = width + padding-kiri + padding-kanan + border-kiri + border-kanan */
.elemen-default {
  box-sizing: content-box;
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  /* Total lebar di layar: 200 + 20 + 20 + 5 + 5 = 250px */
}

/* Nilai MODERN yang disarankan: border-box */
/* width/height sudah mencakup padding dan border */
/* Total lebar = nilai width yang kamu tulis */
.elemen-modern {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  /* Total lebar di layar: tepat 200px */
  /* Area konten = 200 - 20 - 20 - 5 - 5 = 150px */
}

/* Praktik terbaik: terapkan ke semua elemen */
*,
*::before,
*::after {
  box-sizing: border-box;
}

5.2 Width dan Height

.kotak {
  /* Lebar */
  width: 300px;          /* lebar tetap */
  width: 50%;            /* persentase dari lebar induk */
  width: auto;           /* default, browser hitung sendiri */
  width: max-content;    /* selebar konten tanpa wrapping */
  width: min-content;    /* selebar konten terpendek yang memungkinkan */
  width: fit-content;    /* sesuai konten, tapi tidak melebihi induk */

  min-width: 200px;      /* lebar minimum, elemen tidak akan lebih kecil */
  max-width: 800px;      /* lebar maksimum, elemen tidak akan lebih lebar */

  /* Tinggi */
  height: 200px;         /* tinggi tetap */
  height: 50vh;          /* 50% dari tinggi viewport */
  height: auto;          /* tinggi mengikuti konten */

  min-height: 100px;     /* tinggi minimum */
  max-height: 500px;     /* tinggi maksimum */

  /* Shorthand (tidak ada untuk width/height, gunakan secara terpisah) */
}

5.3 Margin

.elemen {
  /* Satu nilai: semua sisi */
  margin: 20px;

  /* Dua nilai: atas-bawah | kiri-kanan */
  margin: 10px 20px;

  /* Tiga nilai: atas | kiri-kanan | bawah */
  margin: 10px 20px 30px;

  /* Empat nilai: atas | kanan | bawah | kiri (searah jarum jam) */
  margin: 10px 20px 30px 40px;

  /* Per sisi */
  margin-top: 10px;
  margin-right: 20px;
  margin-bottom: 10px;
  margin-left: 20px;

  /* Memusatkan elemen secara horizontal (harus ada width) */
  margin: 0 auto;

  /* Nilai negatif - menarik elemen lebih dekat atau melampaui batas */
  margin-top: -10px;

  /* auto pada flex/grid child untuk mendorong ke sisi tertentu */
  margin-left: auto; /* dorong ke kanan */
}

/* Margin Collapsing */
/* Margin atas dan bawah antar elemen BLOK yang bersebelahan akan "runtuh"
   menjadi satu margin sebesar nilai yang terbesar */

.paragraf-1 { margin-bottom: 30px; }
.paragraf-2 { margin-top: 20px; }
/* Jarak di antara keduanya = 30px (bukan 50px!) */

/* Margin collapse TIDAK terjadi pada: */
/* - Elemen float */
/* - Elemen yang di-position absolute/fixed */
/* - Flex dan grid item */
/* - Elemen dengan overflow bukan visible */

5.4 Padding

.elemen {
  /* Shorthand sama seperti margin */
  padding: 20px;
  padding: 10px 20px;
  padding: 10px 20px 30px;
  padding: 10px 20px 30px 40px;

  /* Per sisi */
  padding-top: 10px;
  padding-right: 20px;
  padding-bottom: 10px;
  padding-left: 20px;

  /* Padding tidak bisa bernilai negatif */
  /* Padding mewarisi background dari elemen itu sendiri */
}

6. Satuan Ukuran (Units)

6.1 Satuan Absolut

.elemen {
  /* px - piksel (paling umum) */
  /* 1px pada layar modern bisa = lebih dari 1 piksel fisik (device pixel ratio) */
  font-size: 16px;
  margin: 24px;

  /* pt - poin (1pt = 1/72 inci) - lebih sering digunakan untuk print */
  font-size: 12pt;

  /* cm, mm, in - centimeter, milimeter, inci - untuk print */
  margin: 1cm;
}

6.2 Satuan Relatif

.elemen {
  /* em - relatif terhadap font-size elemen SAAT INI */
  /* Jika font-size elemen = 16px, maka 1em = 16px, 2em = 32px */
  /* BAHAYA: em bersifat compounding (berlipat ganda) pada elemen bersarang */
  font-size: 1.5em;    /* 1.5x dari font-size induk */
  padding: 1em;        /* padding = nilai font-size elemen ini */

  /* rem - relatif terhadap font-size elemen ROOT (html) */
  /* Jauh lebih dapat diprediksi dari em, tidak compounding */
  /* Default browser: 1rem = 16px */
  font-size: 1.5rem;   /* 1.5 x 16px = 24px (tidak peduli nesting) */
  margin: 2rem;        /* 32px */

  /* % - persentase dari nilai properti INDUK */
  width: 50%;          /* setengah lebar induk */
  font-size: 120%;     /* 120% dari font-size induk */

  /* vw - viewport width (1vw = 1% dari lebar viewport) */
  width: 100vw;        /* selebar viewport */
  font-size: 5vw;      /* font responsif terhadap lebar layar */

  /* vh - viewport height (1vh = 1% dari tinggi viewport) */
  height: 100vh;       /* setinggi viewport */
  min-height: 50vh;

  /* vmin - nilai terkecil antara vw dan vh */
  /* vmax - nilai terbesar antara vw dan vh */
  font-size: 5vmin;    /* responsif berdasarkan dimensi terkecil */

  /* svh, lvh, dvh - small/large/dynamic viewport height (modern) */
  /* Berguna untuk mengatasi masalah address bar di mobile */
  height: 100dvh;      /* dynamic viewport height - paling aman untuk mobile */

  /* ch - lebar karakter "0" pada font yang sedang aktif */
  /* Berguna untuk membatasi lebar teks agar mudah dibaca */
  max-width: 65ch;     /* baris teks ideal: 45-75 karakter */
}

6.3 Satuan untuk Warna dan Lainnya

.elemen {
  /* deg - derajat (untuk rotasi, gradient) */
  transform: rotate(45deg);
  background: linear-gradient(90deg, red, blue);

  /* turn - satu putaran penuh (1turn = 360deg) */
  transform: rotate(0.25turn); /* 90 derajat */

  /* rad - radian */
  transform: rotate(1.5708rad); /* ~90 derajat */

  /* s, ms - detik, milidetik (untuk animasi dan transisi) */
  transition-duration: 0.3s;
  animation-duration: 1500ms;

  /* fr - fraction unit (khusus CSS Grid) */
  grid-template-columns: 1fr 2fr; /* kolom kedua dua kali lebih lebar */
}

7. Warna

7.1 Format Penulisan Warna

.elemen {
  /* Named colors - 140+ nama warna bawaan CSS */
  color: red;
  color: navy;
  color: cornflowerblue;
  color: tomato;
  color: transparent; /* benar-benar transparan */

  /* Hexadecimal */
  color: #ff0000;     /* merah, #RRGGBB */
  color: #f00;        /* singkatan 3 digit, sama dengan #ff0000 */
  color: #ff000080;   /* dengan alpha: #RRGGBBAA (80 hex = ~50% opasitas) */
  color: #f008;       /* singkatan dengan alpha */

  /* RGB */
  color: rgb(255, 0, 0);              /* merah */
  color: rgb(255 0 0);                /* sintaks modern (tanpa koma) */
  color: rgba(255, 0, 0, 0.5);        /* dengan alpha 0.5 = 50% transparan */
  color: rgb(255 0 0 / 50%);          /* sintaks modern dengan alpha */

  /* HSL - Hue (0-360), Saturation (%), Lightness (%) */
  /* Lebih intuitif untuk membuat variasi warna */
  color: hsl(0, 100%, 50%);           /* merah */
  color: hsl(120, 100%, 50%);         /* hijau */
  color: hsl(240, 100%, 50%);         /* biru */
  color: hsla(0, 100%, 50%, 0.5);     /* merah 50% transparan */
  color: hsl(0 100% 50% / 50%);       /* sintaks modern */

  /* HWB - Hue, Whiteness, Blackness (CSS Color Level 4) */
  color: hwb(0 0% 0%);                /* merah */

  /* LCH dan LAB - perceptually uniform (CSS Color Level 4) */
  color: lch(50% 100 30);
  color: lab(50% 100 -50);

  /* oklch dan oklab - versi yang lebih akurat (modern) */
  color: oklch(0.6 0.2 30);
}

7.2 Opacity

.elemen {
  /* opacity - mengatur transparansi SELURUH elemen termasuk anaknya */
  /* 0 = sepenuhnya transparan, 1 = sepenuhnya opak */
  opacity: 0.5;    /* 50% transparan */
  opacity: 0;      /* tidak terlihat, tapi masih memakan ruang */

  /* Berbeda dengan alpha di rgba/hsla:
     rgba hanya membuat warna itu sendiri transparan,
     opacity membuat seluruh elemen (termasuk anak) transparan */
}

8. Tipografi

8.1 Font Family

body {
  /* font-family menerima daftar font sebagai fallback */
  /* Browser akan mencoba dari kiri ke kanan */
  font-family: 'Playfair Display', Georgia, 'Times New Roman', serif;
  /*              ^                  ^          ^                  ^
                  Font custom       Sistem      Umum              Generik  */

  /* Nama font dengan spasi HARUS diapit tanda kutip */
  /* Nama tanpa spasi tidak perlu tanda kutip */

  /* Generic font families (fallback terakhir): */
  /* serif      - Times New Roman, Georgia (ada kaki di huruf) */
  /* sans-serif - Arial, Helvetica (tanpa kaki) */
  /* monospace  - Courier, Consolas (lebar karakter sama) */
  /* cursive    - menyerupai tulisan tangan */
  /* fantasy    - dekoratif */
  /* system-ui  - font default sistem operasi */
}

/* Mengimpor Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Source+Sans+3:ital,wght@0,400;0,600;1,400&display=swap');

/* Font dari file lokal menggunakan @font-face */
@font-face {
  font-family: 'FontKustom';        /* nama yang akan digunakan dalam CSS */
  src: url('fonts/custom.woff2') format('woff2'),  /* format modern, prioritas utama */
       url('fonts/custom.woff') format('woff'),    /* fallback */
       url('fonts/custom.ttf') format('truetype'); /* fallback lama */
  font-weight: normal;              /* untuk membedakan variant */
  font-style: normal;
  font-display: swap;               /* teks tampil dengan font sistem dulu, swap saat font dimuat */
}

8.2 Ukuran dan Ketebalan Font

.teks {
  /* font-size */
  font-size: 16px;     /* nilai absolut */
  font-size: 1rem;     /* relatif terhadap root */
  font-size: 1.2em;    /* relatif terhadap induk */
  font-size: large;    /* keyword: xx-small, x-small, small, medium, large, x-large, xx-large */

  /* font-weight - ketebalan huruf */
  font-weight: normal;    /* = 400 */
  font-weight: bold;      /* = 700 */
  font-weight: lighter;   /* lebih ringan dari induk */
  font-weight: bolder;    /* lebih tebal dari induk */
  font-weight: 100;       /* Thin */
  font-weight: 200;       /* Extra Light */
  font-weight: 300;       /* Light */
  font-weight: 400;       /* Regular (normal) */
  font-weight: 500;       /* Medium */
  font-weight: 600;       /* Semi Bold */
  font-weight: 700;       /* Bold */
  font-weight: 800;       /* Extra Bold */
  font-weight: 900;       /* Black */

  /* font-style */
  font-style: normal;
  font-style: italic;     /* miring, menggunakan variant italic jika ada */
  font-style: oblique;    /* miring, font reguler yang di-skew secara digital */
  font-style: oblique 30deg;

  /* font-variant */
  font-variant: normal;
  font-variant: small-caps;  /* huruf kecil menjadi kapital kecil */
}

8.3 Spasi dan Perataan Teks

.teks {
  /* line-height - tinggi baris */
  /* Nilai tanpa satuan (1.5) sangat disarankan: dihitung relatif terhadap font-size */
  line-height: 1.5;      /* 1.5x font-size, responsif */
  line-height: 1.6;      /* nilai umum untuk body text */
  line-height: 24px;     /* nilai absolut, kurang fleksibel */
  line-height: 150%;

  /* letter-spacing - jarak antar huruf (tracking) */
  letter-spacing: 0.05em;  /* sedikit lebih lebar, baik untuk heading */
  letter-spacing: -0.02em; /* lebih rapat, sering untuk display font besar */
  letter-spacing: 0.2em;   /* efek spasi besar untuk all-caps */
  letter-spacing: normal;

  /* word-spacing - jarak antar kata */
  word-spacing: 0.1em;
  word-spacing: 5px;

  /* text-align - perataan horizontal teks */
  text-align: left;      /* rata kiri (default untuk LTR) */
  text-align: right;     /* rata kanan */
  text-align: center;    /* rata tengah */
  text-align: justify;   /* rata kiri dan kanan */
  text-align: start;     /* rata ke awal (mengikuti direction) */
  text-align: end;       /* rata ke akhir */

  /* text-indent - indentasi baris pertama */
  text-indent: 2em;      /* indent paragraf */
  text-indent: -2em;     /* hanging indent */
}

8.4 Dekorasi dan Transformasi Teks

.teks {
  /* text-decoration - garis hiasan teks */
  text-decoration: none;           /* hapus dekorasi (sering untuk link) */
  text-decoration: underline;      /* garis bawah */
  text-decoration: overline;       /* garis atas */
  text-decoration: line-through;   /* coretan */

  /* Shorthand: style | color | thickness */
  text-decoration: underline dotted red;
  text-decoration: underline wavy blue 2px;

  /* Properti terpisah */
  text-decoration-line: underline;
  text-decoration-style: solid | dotted | dashed | double | wavy;
  text-decoration-color: red;
  text-decoration-thickness: 2px;

  /* Garis bawah yang lebih estetik */
  text-underline-offset: 4px;  /* jarak garis bawah dari teks */

  /* text-transform - transformasi huruf */
  text-transform: none;
  text-transform: uppercase;   /* SEMUA HURUF KAPITAL */
  text-transform: lowercase;   /* semua huruf kecil */
  text-transform: capitalize;  /* Setiap Kata Dimulai Kapital */

  /* text-shadow - bayangan teks */
  /* horizontal-offset | vertical-offset | blur-radius | color */
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
  text-shadow: 0 0 10px rgba(255, 255, 0, 0.8); /* efek glow */

  /* Multiple shadows */
  text-shadow:
    1px 1px 0 navy,
    2px 2px 0 blue,
    3px 3px 0 lightblue;
}

8.5 Kontrol White Space dan Overflow Teks

.teks {
  /* white-space - bagaimana spasi dan baris baru dalam HTML ditangani */
  white-space: normal;    /* spasi digabung, teks wrapping (default) */
  white-space: nowrap;    /* tidak wrapping sama sekali */
  white-space: pre;       /* spasi dan newline dipertahankan, tidak wrapping */
  white-space: pre-wrap;  /* spasi dipertahankan, tapi teks wrapping */
  white-space: pre-line;  /* newline dipertahankan, spasi digabung */

  /* word-break - cara memutus kata panjang */
  word-break: normal;     /* default */
  word-break: break-all;  /* putus di mana saja (agresif) */
  word-break: keep-all;   /* jangan putus kata */
  word-break: break-word; /* putus kata panjang jika perlu */

  /* overflow-wrap (word-wrap) */
  overflow-wrap: normal;
  overflow-wrap: break-word; /* putus kata jika tidak ada spasi dan melebihi lebar */

  /* Memotong teks dengan elipsis (...) */
  white-space: nowrap;      /* jangan wrapping */
  overflow: hidden;          /* sembunyikan yang meluap */
  text-overflow: ellipsis;  /* tampilkan "..." */

  /* Multi-line clamp (memotong setelah N baris) */
  display: -webkit-box;
  -webkit-line-clamp: 3;           /* potong setelah 3 baris */
  -webkit-box-orient: vertical;
  overflow: hidden;

  /* Cara modern dengan line-clamp */
  line-clamp: 3;  /* masih dalam perkembangan standar */
}

8.6 Shorthand Font

.teks {
  /* font shorthand: style variant weight size/line-height family */
  /* size dan family WAJIB ada */
  font: italic small-caps bold 18px/1.6 'Georgia', serif;
  /*    ^style  ^variant   ^weight ^size ^line-height ^family */

  /* Contoh lain */
  font: 1.2rem/1.5 'Playfair Display', serif;
  font: bold 14px system-ui;
}

9. Background

9.1 Background Color

.elemen {
  background-color: #3498db;
  background-color: rgba(52, 152, 219, 0.8); /* dengan transparansi */
  background-color: transparent;              /* transparan (default) */
}

9.2 Background Image

.elemen {
  /* background-image */
  background-image: url('foto.jpg');
  background-image: url('https://example.com/gambar.png');
  background-image: none;

  /* background-repeat - apakah gambar diulang */
  background-repeat: repeat;     /* default: diulang di kedua arah */
  background-repeat: repeat-x;   /* hanya horizontal */
  background-repeat: repeat-y;   /* hanya vertikal */
  background-repeat: no-repeat;  /* tidak diulang */
  background-repeat: space;      /* diulang dengan spasi merata */
  background-repeat: round;      /* diulang, skala disesuaikan agar pas */

  /* background-position - posisi gambar */
  background-position: center;         /* tengah */
  background-position: top right;      /* atas kanan */
  background-position: 50% 50%;        /* sama dengan center */
  background-position: 20px 40px;      /* offset dari pojok kiri atas */
  background-position: right 10px bottom 20px; /* offset dari kanan dan bawah */

  /* background-size - ukuran gambar */
  background-size: auto;           /* ukuran asli gambar */
  background-size: 100%;           /* lebar 100%, tinggi auto */
  background-size: 200px 150px;    /* lebar dan tinggi absolut */
  background-size: cover;          /* gambar menutup seluruh area, bisa terpotong */
  background-size: contain;        /* gambar masuk seluruhnya, mungkin ada sisa ruang */

  /* background-attachment - apakah background mengikuti scroll */
  background-attachment: scroll;   /* background ikut scroll dengan konten (default) */
  background-attachment: fixed;    /* background diam, konten scroll di atasnya (parallax) */
  background-attachment: local;    /* background ikut scroll di dalam elemen itu sendiri */

  /* background-origin - titik acuan posisi background */
  background-origin: border-box;   /* dimulai dari pojok border */
  background-origin: padding-box;  /* dimulai dari pojok padding (default) */
  background-origin: content-box;  /* dimulai dari pojok konten */

  /* background-clip - area yang background-nya terlihat */
  background-clip: border-box;     /* background ada di bawah border (default) */
  background-clip: padding-box;    /* background hanya ada di area padding ke dalam */
  background-clip: content-box;    /* background hanya ada di area konten */
  background-clip: text;           /* background terlihat melalui teks (efek keren!) */
}

/* Efek background-clip: text */
.teks-gradien {
  background-image: linear-gradient(45deg, #f06, #48f);
  background-clip: text;
  -webkit-background-clip: text; /* perlu prefix untuk kompatibilitas */
  color: transparent;            /* wajib agar background terlihat */
}

9.3 Gradient

.elemen {
  /* linear-gradient - gradien linier */
  background-image: linear-gradient(red, blue);
  /* arah (opsional): to bottom (default), to right, to top left, 45deg */
  background-image: linear-gradient(to right, red, blue);
  background-image: linear-gradient(45deg, red, blue);
  background-image: linear-gradient(to bottom right, red, yellow, blue);

  /* Menentukan color stop (posisi warna) */
  background-image: linear-gradient(
    to right,
    red 0%,      /* merah mulai dari 0% */
    red 30%,     /* masih merah sampai 30% (tidak ada transisi) */
    blue 30%,    /* langsung biru dari 30% */
    blue 100%
  );

  /* radial-gradient - gradien radial (lingkaran/elips) */
  background-image: radial-gradient(red, blue);
  background-image: radial-gradient(circle, red, blue);   /* bentuk lingkaran */
  background-image: radial-gradient(ellipse, red, blue);  /* elips (default) */
  background-image: radial-gradient(circle at top left, red, blue); /* pusat di pojok */
  background-image: radial-gradient(circle 100px at center, red 50%, blue);

  /* conic-gradient - gradien konik (seperti roda warna) */
  background-image: conic-gradient(red, yellow, green, blue, red);
  background-image: conic-gradient(from 90deg, red, blue); /* mulai dari sudut 90deg */
  background-image: conic-gradient(at 25% 50%, red, blue);

  /* Repeating gradients */
  background-image: repeating-linear-gradient(
    45deg,
    red 0px,
    red 10px,
    white 10px,
    white 20px
  );
}

9.4 Multiple Backgrounds

/* CSS mendukung beberapa background sekaligus, urutan = layer dari atas ke bawah */
.elemen {
  background-image:
    url('overlay.png'),           /* paling atas */
    linear-gradient(#000, #fff),  /* di bawahnya */
    url('texture.jpg');           /* paling bawah */

  background-size: contain, cover, cover;
  background-repeat: no-repeat, no-repeat, repeat;
  background-position: center, center, center;

  /* background-color selalu di layer paling bawah */
  background-color: #f0f0f0;
}

9.5 Shorthand Background

.elemen {
  /* background: color image repeat position/size attachment origin clip */
  background: #fff url('gambar.jpg') no-repeat center/cover fixed;

  /* Cukup tulis yang diperlukan saja */
  background: linear-gradient(135deg, #667eea, #764ba2);
}

10. Border

10.1 Border Dasar

.elemen {
  /* Shorthand: width style color */
  border: 2px solid #333;

  /* Per sisi */
  border-top: 3px dashed red;
  border-right: 1px solid gray;
  border-bottom: 2px dotted blue;
  border-left: 0; /* atau: border-left: none; */

  /* Properti terpisah */
  border-width: 1px;          /* atau: 1px 2px 1px 2px */
  border-style: solid;        /* wajib ada agar border terlihat! */
  border-color: #333;

  /* Nilai border-style: */
  /* none, hidden, solid, dashed, dotted, double, groove, ridge, inset, outset */

  /* Menghapus border */
  border: none;
  border: 0;
}

10.2 Border Radius

.elemen {
  /* border-radius: membulatkan sudut */
  border-radius: 8px;           /* semua sudut */
  border-radius: 50%;           /* lingkaran jika width = height */
  border-radius: 10px 20px;     /* atas-kiri/bawah-kanan | atas-kanan/bawah-kiri */
  border-radius: 10px 20px 30px 40px; /* tl | tr | br | bl (searah jarum jam) */

  /* Per sudut */
  border-top-left-radius: 10px;
  border-top-right-radius: 20px;
  border-bottom-right-radius: 30px;
  border-bottom-left-radius: 40px;

  /* Radius elips: horizontal-radius / vertical-radius */
  border-radius: 50px / 30px;   /* sudut berbentuk elips */
  border-top-left-radius: 30px 60px; /* 30px horizontal, 60px vertikal */
}

10.3 Outline

.elemen {
  /* Outline: mirip border, tapi TIDAK mempengaruhi layout (di luar border) */
  /* Sering digunakan oleh browser untuk menandai elemen yang fokus */
  outline: 2px solid blue;
  outline: 3px dashed rgba(0, 100, 255, 0.5);

  outline-width: 2px;
  outline-style: solid;
  outline-color: blue;
  outline-offset: 4px; /* jarak antara outline dan border */

  /* Jangan hapus outline untuk alasan aksesibilitas! */
  /* Ini penting untuk pengguna keyboard */
  /* Jika ingin kustom, ganti dengan desain yang tetap terlihat */
  outline: none;  /* HANYA jika ada alternatif visual yang jelas */
}

11. Display dan Visibility

11.1 Display

Properti display adalah salah satu yang paling mendasar dan paling berpengaruh dalam CSS.

.elemen {
  /* display: block */
  /* - Mengambil lebar penuh yang tersedia */
  /* - Selalu dimulai di baris baru */
  /* - Bisa diberi width, height, margin, padding secara penuh */
  /* Contoh default: div, p, h1-h6, ul, li, section, article, header, footer */
  display: block;

  /* display: inline */
  /* - Hanya mengambil lebar sebesar kontennya */
  /* - Tidak memulai baris baru */
  /* - width dan height TIDAK berpengaruh */
  /* - margin dan padding hanya berlaku horizontal */
  /* Contoh default: span, a, strong, em, img, input */
  display: inline;

  /* display: inline-block */
  /* - Mengalir seperti inline (tidak memulai baris baru) */
  /* - Bisa diberi width, height, margin, padding seperti block */
  display: inline-block;

  /* display: flex */
  /* Mengaktifkan Flexbox pada elemen ini (menjadi flex container) */
  display: flex;
  display: inline-flex; /* flex container yang inline */

  /* display: grid */
  /* Mengaktifkan CSS Grid pada elemen ini (menjadi grid container) */
  display: grid;
  display: inline-grid; /* grid container yang inline */

  /* display: none */
  /* Elemen sama sekali tidak ditampilkan, tidak memakan ruang */
  /* Berbeda dengan visibility: hidden yang menyembunyikan tapi masih memakan ruang */
  display: none;

  /* display: table - meniru perilaku tabel HTML */
  display: table;
  display: table-row;
  display: table-cell;

  /* display: list-item - menjadikan elemen berperilaku seperti <li> */
  display: list-item;

  /* display: contents - elemen sendiri hilang dari box tree, tapi anaknya tetap ada */
  /* Berguna untuk wrapper yang tidak ingin mempengaruhi layout */
  display: contents;
}

11.2 Visibility dan Opacity

.elemen {
  /* visibility - mengontrol visibilitas */
  visibility: visible;   /* terlihat (default) */
  visibility: hidden;    /* tidak terlihat, MASIH memakan ruang */
  visibility: collapse;  /* untuk row/column tabel: kolaps tanpa memakan ruang */

  /* opacity - transparansi */
  opacity: 1;    /* sepenuhnya terlihat */
  opacity: 0;    /* sepenuhnya transparan, MASIH memakan ruang dan bisa diklik! */
  opacity: 0.5;  /* setengah transparan */

  /* Perbandingan cara menyembunyikan elemen: */
  /* display: none      -> tidak ada, tidak memakan ruang, tidak bisa diklik */
  /* visibility: hidden -> transparan tapi memakan ruang, tidak bisa diklik */
  /* opacity: 0         -> transparan tapi memakan ruang, MASIH bisa diklik */
}

12. Positioning

Properti position mengontrol bagaimana elemen ditempatkan di halaman.

.elemen {
  /* position: static (DEFAULT) */
  /* Elemen mengikuti alur normal dokumen */
  /* Properti top, right, bottom, left, z-index TIDAK berpengaruh */
  position: static;

  /* position: relative */
  /* Elemen tetap di alur normal, tapi BISA digeser */
  /* Pergeseran relatif terhadap POSISI NORMAL-nya sendiri */
  /* Ruang aslinya di alur dokumen TETAP RESERVASI */
  position: relative;
  top: 10px;     /* geser 10px ke bawah dari posisi normal */
  left: 20px;    /* geser 20px ke kanan dari posisi normal */

  /* position: absolute */
  /* Elemen KELUAR dari alur normal dokumen */
  /* Posisi relatif terhadap ANCESTOR terdekat yang ber-position (bukan static) */
  /* Jika tidak ada, relatif terhadap initial containing block (viewport) */
  /* Ruangnya di alur dokumen TIDAK lagi direservasi */
  position: absolute;
  top: 0;
  right: 0;
  /* Elemen ini akan berada di pojok kanan atas ancestor-nya yang ber-position */

  /* position: fixed */
  /* Elemen KELUAR dari alur normal */
  /* Posisi relatif terhadap VIEWPORT, tidak bergerak saat scroll */
  /* Digunakan untuk: header sticky, popup, tombol "kembali ke atas" */
  position: fixed;
  bottom: 20px;
  right: 20px;

  /* position: sticky */
  /* Kombinasi relative dan fixed */
  /* Berperilaku relative SAMPAI mencapai ambang batas yang ditentukan,
     lalu berperilaku fixed */
  /* Harus ada threshold (top/bottom/left/right) */
  position: sticky;
  top: 0; /* menempel di atas saat scroll mencapai posisi ini */
}

12.1 Pola Umum Positioning

/* Pola: menempatkan child di tengah parent */
.parent {
  position: relative; /* ini yang menjadi acuan absolute positioning */
  width: 400px;
  height: 300px;
}

/* Cara klasik memusatkan dengan absolute */
.child-absolut {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* pindahkan kembali setengah ukuran diri sendiri */
}

/* Badge di pojok kanan atas */
.tombol-notif {
  position: relative;
  display: inline-block;
}

.badge {
  position: absolute;
  top: -8px;
  right: -8px;
  background: red;
  color: white;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

13. Float dan Clear

Float adalah mekanisme layout lama yang kini jarang digunakan untuk layout (digantikan Flexbox/Grid), namun masih digunakan untuk membuat teks mengalir di sekitar gambar.

.gambar {
  /* float: membuat elemen mengapung ke sisi tertentu */
  float: left;   /* gambar di kiri, teks mengalir di kanannya */
  float: right;  /* gambar di kanan, teks mengalir di kirinya */
  float: none;   /* default */
  margin: 0 16px 16px 0; /* beri jarak antara gambar dan teks */
}

/* clear: mencegah elemen mengalir di samping float */
.setelah-float {
  clear: left;   /* tidak mengalir di samping float kiri */
  clear: right;  /* tidak mengalir di samping float kanan */
  clear: both;   /* tidak mengalir di samping float manapun */
}

/* Clearfix - solusi untuk parent yang anaknya semua float
   (parent collapsing problem) */
.container::after {
  content: "";
  display: table;
  clear: both;
}

/* Atau gunakan overflow: hidden pada parent */
.container {
  overflow: hidden; /* juga menyelesaikan masalah parent collapse */
}

14. Flexbox

Flexbox (Flexible Box Layout) adalah sistem layout satu dimensi yang sangat powerful untuk mendistribusikan ruang dan menyelaraskan item dalam sebuah container.

Konsep inti:

  • Flex Container: Elemen yang display: flex diterapkan. Ini menjadi induk yang mengendalikan layout.
  • Flex Item: Elemen anak langsung dari flex container.
  • Main Axis: Sumbu utama, arah default adalah horizontal (kiri ke kanan).
  • Cross Axis: Sumbu silang, tegak lurus dengan main axis (atas ke bawah secara default).
Flex Container
+---------------------------------------------------------------+
| Main Axis (flex-direction: row) -->                           |
|                                                               |
| +---------+  +---------+  +---------+                        |
| |         |  |         |  |         |  ^ Cross Axis          |
| | Item 1  |  | Item 2  |  | Item 3  |  |                     |
| |         |  |         |  |         |  v                     |
| +---------+  +---------+  +---------+                        |
+---------------------------------------------------------------+

14.1 Properti Flex Container

.flex-container {
  display: flex;        /* aktifkan flexbox */
  display: inline-flex; /* flex container yang bersifat inline */


  /* ====================================================
     flex-direction: arah main axis
     ==================================================== */
  flex-direction: row;            /* kiri ke kanan (default) */
  flex-direction: row-reverse;    /* kanan ke kiri */
  flex-direction: column;         /* atas ke bawah */
  flex-direction: column-reverse; /* bawah ke atas */


  /* ====================================================
     flex-wrap: apakah item boleh pindah baris
     ==================================================== */
  flex-wrap: nowrap;         /* semua di satu baris (default), bisa overflow */
  flex-wrap: wrap;           /* item pindah baris jika tidak muat */
  flex-wrap: wrap-reverse;   /* item pindah baris ke atas */


  /* ====================================================
     flex-flow: shorthand untuk flex-direction + flex-wrap
     ==================================================== */
  flex-flow: row wrap;
  flex-flow: column nowrap;


  /* ====================================================
     justify-content: perataan item di MAIN AXIS
     ==================================================== */
  justify-content: flex-start;    /* kiri (default untuk row) */
  justify-content: flex-end;      /* kanan */
  justify-content: center;        /* tengah */
  justify-content: space-between; /* sisi tepi tidak ada spasi, antar item ada */
  justify-content: space-around;  /* setiap item ada spasi di kiri dan kanan */
  justify-content: space-evenly;  /* spasi merata termasuk sisi tepi */


  /* ====================================================
     align-items: perataan item di CROSS AXIS
     (berlaku untuk satu baris)
     ==================================================== */
  align-items: stretch;     /* item direntangkan memenuhi cross axis (default) */
  align-items: flex-start;  /* item di awal cross axis (atas untuk row) */
  align-items: flex-end;    /* item di akhir cross axis (bawah untuk row) */
  align-items: center;      /* item di tengah cross axis */
  align-items: baseline;    /* item disejajarkan berdasarkan baseline teks */


  /* ====================================================
     align-content: perataan BARIS item di CROSS AXIS
     (hanya berlaku jika ada lebih dari satu baris - flex-wrap: wrap)
     ==================================================== */
  align-content: stretch;       /* baris direntangkan (default) */
  align-content: flex-start;    /* semua baris di atas */
  align-content: flex-end;      /* semua baris di bawah */
  align-content: center;        /* semua baris di tengah */
  align-content: space-between; /* baris di atas dan bawah, sisa rata */
  align-content: space-around;  /* spasi merata di atas dan bawah setiap baris */
  align-content: space-evenly;  /* spasi merata termasuk tepi */


  /* ====================================================
     gap: jarak antar flex item
     ==================================================== */
  gap: 16px;            /* jarak sama di semua arah */
  gap: 16px 24px;       /* row-gap | column-gap */
  row-gap: 16px;        /* jarak antar baris */
  column-gap: 24px;     /* jarak antar kolom */
}

14.2 Properti Flex Item

.flex-item {
  /* ====================================================
     order: urutan tampilan item (bukan urutan HTML)
     Default semua item: 0
     Makin kecil angkanya, makin awal tampil
     ==================================================== */
  order: 0;    /* default */
  order: -1;   /* tampil sebelum item dengan order 0 */
  order: 2;    /* tampil setelah item dengan order 0 dan 1 */


  /* ====================================================
     flex-grow: kemampuan item untuk MEMBESAR mengisi ruang kosong
     Default: 0 (tidak tumbuh)
     Angkanya adalah proporsi relatif antar item
     ==================================================== */
  flex-grow: 0;   /* tidak tumbuh */
  flex-grow: 1;   /* tumbuh mengambil sisa ruang */
  flex-grow: 2;   /* tumbuh dua kali lebih cepat dari item dengan flex-grow: 1 */


  /* ====================================================
     flex-shrink: kemampuan item untuk MENGECIL jika tidak ada ruang
     Default: 1 (bisa mengecil)
     ==================================================== */
  flex-shrink: 1;   /* bisa mengecil (default) */
  flex-shrink: 0;   /* tidak boleh mengecil, pertahankan ukuran asli */
  flex-shrink: 2;   /* mengecil lebih cepat dari item dengan flex-shrink: 1 */


  /* ====================================================
     flex-basis: ukuran AWAL item sebelum ruang tersisa dibagi
     Menggantikan width (untuk row) atau height (untuk column)
     ==================================================== */
  flex-basis: auto;     /* gunakan ukuran konten (default) */
  flex-basis: 0;        /* mulai dari nol, semua ruang dianggap "tersisa" */
  flex-basis: 200px;    /* ukuran awal 200px */
  flex-basis: 25%;      /* 25% dari container */


  /* ====================================================
     flex: shorthand untuk grow | shrink | basis
     ==================================================== */
  flex: 0 1 auto;     /* default: tidak tumbuh, bisa mengecil, ukuran auto */
  flex: 1;            /* shorthand untuk: 1 1 0 (tumbuh dan mengecil, basis nol) */
  flex: auto;         /* shorthand untuk: 1 1 auto */
  flex: none;         /* shorthand untuk: 0 0 auto (tidak fleksibel sama sekali) */
  flex: 1 1 200px;    /* tumbuh, mengecil, basis 200px */


  /* ====================================================
     align-self: override align-items untuk item TERTENTU
     ==================================================== */
  align-self: auto;        /* ikuti align-items container (default) */
  align-self: flex-start;
  align-self: flex-end;
  align-self: center;
  align-self: stretch;
  align-self: baseline;
}

14.3 Pola Layout dengan Flexbox

/* Centering sempurna (vertikal dan horizontal) */
.pusatkan-ini {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Navigation bar */
.navbar {
  display: flex;
  justify-content: space-between; /* logo kiri, menu kanan */
  align-items: center;
  padding: 0 24px;
}

/* Kartu yang tingginya sama */
.grid-kartu {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.kartu {
  flex: 1 1 280px; /* tumbuh, mengecil, minimal 280px */
  /* Semua kartu akan tingginya sama karena align-items: stretch (default) */
}

/* Footer selalu di bawah */
.halaman {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.konten-utama {
  flex: 1; /* mengambil semua sisa ruang, mendorong footer ke bawah */
}

/* Membagi kolom dengan rasio tertentu */
.layout-dua-kolom {
  display: flex;
  gap: 24px;
}
.sidebar { flex: 0 0 280px; }   /* lebar tetap 280px */
.konten  { flex: 1; }           /* sisanya */

15. CSS Grid

CSS Grid adalah sistem layout dua dimensi yang memungkinkan kontrol penuh atas baris DAN kolom secara bersamaan.

Konsep inti:

  • Grid Container: Elemen yang display: grid diterapkan.
  • Grid Item: Elemen anak langsung dari grid container.
  • Grid Line: Garis pembatas antar kolom/baris, dinomori dari 1.
  • Grid Track: Ruang di antara dua grid line (satu kolom atau satu baris).
  • Grid Cell: Satu "sel" persilangan antara satu kolom dan satu baris.
  • Grid Area: Rectangular area yang terdiri dari satu atau lebih grid cell.
Grid Container
     Col 1    Col 2    Col 3
   |        |        |        |
-- +--------+--------+--------+ -- Row 1
   | Cell   | Cell   | Cell   |
-- +--------+--------+--------+ -- Row 2
   | Cell   | Cell   | Cell   |
-- +--------+--------+--------+ -- Row 3

Grid Line: angka 1, 2, 3, 4 (ada 4 line untuk 3 kolom)

15.1 Mendefinisikan Kolom dan Baris

.grid-container {
  display: grid;

  /* ====================================================
     grid-template-columns: mendefinisikan kolom
     ==================================================== */
  grid-template-columns: 200px 200px 200px;   /* 3 kolom 200px */
  grid-template-columns: 1fr 1fr 1fr;         /* 3 kolom sama lebar (fraction) */
  grid-template-columns: 1fr 2fr 1fr;         /* tengah dua kali lebih lebar */
  grid-template-columns: 200px 1fr;           /* sidebar 200px, konten sisa */
  grid-template-columns: auto auto auto;       /* lebar mengikuti konten */

  /* repeat() - mengulangi pola */
  grid-template-columns: repeat(3, 1fr);       /* sama dengan 1fr 1fr 1fr */
  grid-template-columns: repeat(4, 200px);
  grid-template-columns: repeat(3, 1fr 2fr);  /* pola 1fr 2fr diulang 3x = 6 kolom */

  /* minmax() - ukuran antara minimum dan maksimum */
  grid-template-columns: repeat(3, minmax(200px, 1fr));
  /* setiap kolom minimal 200px, maksimal 1fr */

  /* auto-fill vs auto-fit */
  /* auto-fill: isi sebanyak kolom yang muat, meski ada yang kosong */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  /* auto-fit: seperti auto-fill, tapi kolom kosong "diciutkan" */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  /* Ini adalah pola responsive yang sangat powerful tanpa media query! */


  /* ====================================================
     grid-template-rows: mendefinisikan baris
     ==================================================== */
  grid-template-rows: 60px auto 80px;  /* header | konten | footer */
  grid-template-rows: repeat(3, 100px);
  grid-template-rows: 1fr 2fr;


  /* ====================================================
     grid-template: shorthand untuk columns dan rows
     ==================================================== */
  grid-template: repeat(3, 100px) / repeat(3, 1fr);
  /* rows / columns */


  /* ====================================================
     gap: jarak antar sel grid
     ==================================================== */
  gap: 16px;
  gap: 24px 16px;   /* row-gap | column-gap */
  row-gap: 24px;
  column-gap: 16px;
}

15.2 Implicit Grid (Grid Otomatis)

Ketika item lebih banyak dari sel yang didefinisikan, grid secara otomatis membuat baris/kolom baru (implicit grid).

.grid-container {
  /* grid-auto-rows: ukuran baris yang dibuat otomatis */
  grid-auto-rows: 150px;
  grid-auto-rows: minmax(100px, auto); /* minimal 100px, maksimal ikuti konten */

  /* grid-auto-columns: ukuran kolom yang dibuat otomatis */
  grid-auto-columns: 1fr;

  /* grid-auto-flow: arah penempatan item otomatis */
  grid-auto-flow: row;     /* isi baris dulu (default) */
  grid-auto-flow: column;  /* isi kolom dulu */
  grid-auto-flow: dense;   /* isi celah kosong (berguna untuk layout masonry-like) */
  grid-auto-flow: row dense;
}

15.3 Grid Template Areas

Cara visual yang intuitif untuk mendefinisikan layout grid menggunakan nama area.

.halaman {
  display: grid;
  grid-template-areas:
    "header  header  header"   /* baris 1: header di ketiga kolom */
    "sidebar konten  konten"   /* baris 2: sidebar 1 kolom, konten 2 kolom */
    "footer  footer  footer";  /* baris 3: footer di ketiga kolom */
  grid-template-columns: 250px 1fr 1fr;
  grid-template-rows: 60px auto 80px;
  min-height: 100vh;
  gap: 16px;
}

/* Elemen anak menggunakan nama area */
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.konten  { grid-area: konten; }
.footer  { grid-area: footer; }

/* Gunakan titik (.) untuk sel kosong */
.grid-dengan-celah {
  grid-template-areas:
    "logo  .  .  nav"
    "hero  hero hero hero"
    ".     .   .    .";
}

15.4 Menempatkan Grid Item

.grid-item {
  /* ====================================================
     Menempatkan berdasarkan nomor grid line
     ==================================================== */

  /* grid-column: start / end */
  grid-column: 1 / 3;    /* dari line 1 sampai line 3 (mengisi 2 kolom) */
  grid-column: 2 / 4;    /* dari line 2 sampai line 4 */
  grid-column: 1 / -1;   /* dari awal sampai akhir (angka negatif dari kanan) */

  /* Menggunakan span: berapa kolom/baris yang diambil */
  grid-column: 1 / span 2;  /* mulai dari line 1, selebar 2 kolom */
  grid-column: span 3;       /* selebar 3 kolom (posisi ditentukan auto) */

  /* Per properti */
  grid-column-start: 1;
  grid-column-end: 3;

  /* grid-row: start / end */
  grid-row: 1 / 3;      /* dari row line 1 sampai 3 */
  grid-row: span 2;      /* setinggi 2 baris */

  grid-row-start: 1;
  grid-row-end: 3;

  /* ====================================================
     grid-area: shorthand lengkap
     row-start / column-start / row-end / column-end
     ==================================================== */
  grid-area: 1 / 1 / 3 / 4; /* baris 1-3, kolom 1-4 */

  /* Atau menggunakan nama area yang sudah didefinisikan */
  grid-area: header;
}

15.5 Perataan di dalam Grid

/* Perataan ITEM di dalam grid cell */
.grid-container {
  /* justify-items: perataan horizontal semua item */
  justify-items: stretch;  /* default: item memenuhi lebar cell */
  justify-items: start;
  justify-items: end;
  justify-items: center;

  /* align-items: perataan vertikal semua item */
  align-items: stretch;    /* default: item memenuhi tinggi cell */
  align-items: start;
  align-items: end;
  align-items: center;

  /* place-items: shorthand align-items | justify-items */
  place-items: center;         /* keduanya center */
  place-items: start end;      /* align: start, justify: end */
}

/* Perataan GRID TRACKS di dalam container */
.grid-container {
  /* justify-content: perataan kolom-kolom grid secara horizontal */
  justify-content: start;        /* default */
  justify-content: end;
  justify-content: center;
  justify-content: space-between;
  justify-content: space-around;
  justify-content: space-evenly;

  /* align-content: perataan baris-baris grid secara vertikal */
  align-content: start;          /* default */
  align-content: end;
  align-content: center;
  align-content: space-between;

  /* place-content: shorthand align-content | justify-content */
  place-content: center;
  place-content: space-between center;
}

/* Override untuk satu item tertentu */
.grid-item {
  justify-self: center;   /* override justify-items untuk item ini */
  align-self: end;        /* override align-items untuk item ini */
  place-self: center end;
}

15.6 Named Grid Lines

/* Memberi nama pada grid line untuk referensi yang lebih mudah */
.grid-container {
  grid-template-columns:
    [sidebar-start] 250px [sidebar-end content-start] 1fr [content-end];
  grid-template-rows:
    [header-start] 60px [header-end main-start] auto [main-end footer-start] 80px [footer-end];
}

.header {
  grid-column: sidebar-start / content-end; /* dari awal sidebar sampai akhir content */
  grid-row: header-start / header-end;
}

.sidebar {
  grid-column: sidebar-start / sidebar-end;
  grid-row: main-start / main-end;
}

15.7 Pola Layout Grid yang Umum

/* Layout responsif tanpa media query */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

/* Layout Holy Grail (header, sidebar, konten, sidebar, footer) */
.holy-grail {
  display: grid;
  grid-template:
    "header header header" 60px
    "nav    main   aside"  1fr
    "footer footer footer" 80px
    / 180px 1fr 160px;
  min-height: 100vh;
}

/* Overlap/Layering dengan grid */
.hero-section {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
}
.hero-gambar,
.hero-teks {
  grid-area: 1 / 1; /* keduanya di cell yang sama, teks di atas gambar */
}
.hero-teks {
  z-index: 1;
  align-self: center;
  justify-self: center;
}

16. Overflow

.elemen {
  /* overflow: bagaimana menangani konten yang melebihi batas elemen */

  overflow: visible;  /* konten tetap terlihat meskipun meluap (default) */
  overflow: hidden;   /* konten yang meluap disembunyikan */
  overflow: scroll;   /* selalu tampilkan scrollbar */
  overflow: auto;     /* tampilkan scrollbar hanya jika diperlukan */
  overflow: clip;     /* seperti hidden, tapi tidak membuat formatting context baru */

  /* Kontrol per sumbu */
  overflow-x: auto;   /* horizontal: tampilkan scrollbar jika perlu */
  overflow-y: hidden; /* vertikal: sembunyikan yang meluap */

  /* overflow-x: visible dengan overflow-y yang lain tidak valid */
  /* Jika satu sumbu bukan visible, sumbu lainnya otomatis jadi auto */

  /* Scroll behavior */
  scroll-behavior: smooth;   /* animasi halus saat scroll ke anchor */
  scroll-behavior: auto;     /* scroll instan */

  /* Snap scrolling */
  scroll-snap-type: x mandatory;   /* snap horizontal, wajib berhenti di snap point */
  scroll-snap-type: y proximity;   /* snap vertikal, snap jika cukup dekat */
  scroll-padding-top: 60px;        /* kompensasi untuk fixed header */
}

.snap-item {
  scroll-snap-align: start;   /* item ini snap di tepi awal */
  scroll-snap-align: center;  /* item ini snap di tengah */
  scroll-snap-align: end;     /* item ini snap di tepi akhir */
  scroll-snap-stop: always;   /* selalu berhenti di sini, tidak bisa dilewati */
}

17. Transformasi (Transform)

Properti transform mengubah tampilan elemen (posisi, rotasi, skala) tanpa mempengaruhi layout elemen lain.

.elemen {
  /* translate - memindahkan posisi */
  transform: translateX(50px);      /* geser 50px ke kanan */
  transform: translateY(-20px);     /* geser 20px ke atas */
  transform: translate(50px, -20px); /* geser horizontal dan vertikal */
  transform: translateZ(30px);      /* geser ke arah Z (butuh perspective) */
  transform: translate3d(50px, -20px, 30px);

  /* rotate - memutar elemen */
  transform: rotate(45deg);         /* putar 45 derajat searah jarum jam */
  transform: rotate(-90deg);        /* putar 90 derajat berlawanan jarum jam */
  transform: rotateX(45deg);        /* putar pada sumbu X (3D, butuh perspective) */
  transform: rotateY(180deg);       /* efek "flip kartu" */
  transform: rotateZ(30deg);        /* sama dengan rotate() */
  transform: rotate3d(1, 1, 0, 45deg); /* putar pada sumbu x=1, y=1, z=0 sebesar 45deg */

  /* scale - mengubah ukuran */
  transform: scale(1.5);            /* perbesar 1.5x */
  transform: scale(0.5);            /* perkecil jadi setengah */
  transform: scaleX(2);             /* perlebar 2x */
  transform: scaleY(0.5);           /* perkecil tinggi jadi setengah */
  transform: scale(1.2, 0.8);       /* x dan y berbeda */

  /* skew - memiringkan elemen */
  transform: skewX(20deg);
  transform: skewY(-10deg);
  transform: skew(20deg, -10deg);

  /* matrix - transformasi 2D kompleks dalam satu fungsi */
  /* matrix(a, b, c, d, tx, ty) - untuk penggunaan lanjutan */

  /* Menggabungkan beberapa transformasi */
  transform: translateX(100px) rotate(45deg) scale(1.2);
  /* Urutan sangat mempengaruhi hasil! */
  /* Dieksekusi dari kanan ke kiri */


  /* transform-origin: titik acuan transformasi */
  transform-origin: center;            /* default: 50% 50% */
  transform-origin: top left;          /* pojok kiri atas */
  transform-origin: 0 0;               /* sama dengan top left */
  transform-origin: right bottom;
  transform-origin: 50% 100%;          /* tengah bawah */
  transform-origin: 20px 40px;         /* koordinat absolut */


  /* perspective: kedalaman efek 3D */
  /* Semakin kecil nilainya, efek 3D semakin ekstrem */
  perspective: 800px;

  /* transform-style: apakah anak elemen juga dalam 3D space */
  transform-style: flat;          /* default: anak tetap di 2D */
  transform-style: preserve-3d;  /* anak ikut dalam 3D space */

  /* backface-visibility: apakah sisi belakang elemen terlihat saat diputar */
  backface-visibility: visible;   /* default */
  backface-visibility: hidden;    /* sembunyikan sisi belakang (untuk flip card) */
}

/* translate() sebagai properti terpisah (modern, lebih performa) */
.elemen-modern {
  translate: 50px 20px;   /* atau: 50px -20px */
  rotate: 45deg;
  scale: 1.2;
}

18. Transisi (Transition)

Transition menambahkan animasi halus saat properti CSS berubah nilainya.

.elemen {
  /* transition-property: properti mana yang akan dianimasikan */
  transition-property: background-color;  /* hanya background-color */
  transition-property: all;              /* semua properti yang berubah */
  transition-property: opacity, transform; /* beberapa properti */
  transition-property: none;             /* tidak ada transisi */

  /* transition-duration: berapa lama animasi */
  transition-duration: 0.3s;    /* 300 milidetik */
  transition-duration: 500ms;   /* 500 milidetik */

  /* transition-timing-function: kurva kecepatan animasi */
  transition-timing-function: ease;          /* default: lambat-cepat-lambat */
  transition-timing-function: linear;        /* kecepatan konstan */
  transition-timing-function: ease-in;       /* mulai lambat, akhir cepat */
  transition-timing-function: ease-out;      /* mulai cepat, akhir lambat */
  transition-timing-function: ease-in-out;   /* lambat di awal dan akhir */
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* custom curve */
  transition-timing-function: steps(5, end);  /* animasi a-step-a-step */

  /* transition-delay: tunda sebelum animasi dimulai */
  transition-delay: 0s;     /* tanpa tunda (default) */
  transition-delay: 0.2s;   /* tunda 200ms */
  transition-delay: -0.1s;  /* negatif: mulai di tengah animasi */

  /* Shorthand: property duration timing-function delay */
  transition: background-color 0.3s ease;
  transition: all 0.4s ease-in-out;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);

  /* Nilai awal yang akan bertransisi */
  background-color: white;
  transform: scale(1);
  opacity: 1;
}

/* State yang memicu transisi */
.elemen:hover {
  background-color: #3498db;
  transform: scale(1.05) translateY(-4px);
  opacity: 0.9;
}

/* Contoh tombol dengan multiple transitions */
.tombol {
  background: #2ecc71;
  color: white;
  padding: 12px 24px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  transform: translateY(0);
  transition:
    background-color 0.2s ease,
    box-shadow 0.2s ease,
    transform 0.15s ease;
}

.tombol:hover {
  background: #27ae60;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
  transform: translateY(-2px);
}

.tombol:active {
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

19. Animasi (Animation)

CSS Animation memungkinkan animasi yang lebih kompleks dan bisa berjalan otomatis tanpa interaksi pengguna.

19.1 @keyframes

/* Mendefinisikan keyframe animation */
/* Nama bisa apa saja, akan direferensi di animation-name */

/* Menggunakan from dan to (dua keyframe) */
@keyframes namaAnimasi {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Menggunakan persentase (banyak keyframe) */
@keyframes gerakBounce {
  0% {
    transform: translateY(0);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(-60px);
    animation-timing-function: ease-in;
  }
  80% {
    transform: translateY(-20px);
    animation-timing-function: ease-out;
  }
  90% {
    transform: translateY(-10px);
    animation-timing-function: ease-in;
  }
  100% {
    transform: translateY(0);
  }
}

@keyframes berputar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes warnaGanti {
  0%   { background-color: red; }
  33%  { background-color: blue; }
  66%  { background-color: green; }
  100% { background-color: red; }
}

@keyframes faedIn {
  from {
    opacity: 0;
    transform: scale(0.95) translateY(10px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

19.2 Properti Animation

.elemen {
  /* animation-name: nama keyframe yang akan digunakan */
  animation-name: namaAnimasi;
  animation-name: none; /* tidak ada animasi */

  /* animation-duration: berapa lama satu siklus animasi */
  animation-duration: 1s;
  animation-duration: 500ms;

  /* animation-timing-function: kurva kecepatan */
  animation-timing-function: ease;
  animation-timing-function: linear;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  animation-timing-function: steps(4, end); /* 4 langkah, berpindah di akhir setiap langkah */

  /* animation-delay: tunda sebelum animasi mulai */
  animation-delay: 0.2s;
  animation-delay: -0.5s; /* mulai dari titik 0.5s di dalam animasi */

  /* animation-iteration-count: berapa kali animasi diulang */
  animation-iteration-count: 1;        /* sekali (default) */
  animation-iteration-count: 3;        /* tiga kali */
  animation-iteration-count: infinite; /* terus menerus */

  /* animation-direction: arah animasi */
  animation-direction: normal;            /* dari from ke to (default) */
  animation-direction: reverse;           /* dari to ke from */
  animation-direction: alternate;         /* from->to, lalu to->from, dst */
  animation-direction: alternate-reverse; /* to->from, lalu from->to, dst */

  /* animation-fill-mode: status elemen sebelum/setelah animasi */
  animation-fill-mode: none;       /* kembali ke state awal (default) */
  animation-fill-mode: forwards;   /* pertahankan state terakhir animasi setelah selesai */
  animation-fill-mode: backwards;  /* terapkan state from saat delay */
  animation-fill-mode: both;       /* gabungan forwards dan backwards */

  /* animation-play-state: pause atau jalan */
  animation-play-state: running;   /* default */
  animation-play-state: paused;    /* animasi berhenti sementara */

  /* ====================================================
     Shorthand: name duration timing-function delay
                iteration-count direction fill-mode play-state
     ==================================================== */
  animation: namaAnimasi 1s ease 0s 1 normal forwards;

  /* Contoh ringkas */
  animation: namaAnimasi 0.5s ease forwards;
  animation: berputar 2s linear infinite;

  /* Beberapa animasi sekaligus, dipisah koma */
  animation:
    faedIn 0.5s ease forwards,
    berputar 2s linear 0.5s infinite;
}

/* Menghentikan animasi saat hover */
.elemen:hover {
  animation-play-state: paused;
}

/* Animasi bergantung pada preferensi pengguna (aksesibilitas) */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

20. CSS Custom Properties (Variabel CSS)

CSS Custom Properties (sering disebut CSS Variables) memungkinkan kita mendefinisikan nilai yang bisa digunakan kembali di seluruh stylesheet.

/* ====================================================
   Mendefinisikan variabel
   Biasanya di :root agar tersedia global
   ==================================================== */
:root {
  /* Variabel dimulai dengan dua tanda hubung (--) */
  --warna-primer:     #2563eb;
  --warna-sekunder:   #7c3aed;
  --warna-aksen:      #f59e0b;
  --warna-bahaya:     #ef4444;
  --warna-sukses:     #22c55e;

  --warna-teks:       #1f2937;
  --warna-teks-ringan: #6b7280;
  --warna-bg:         #ffffff;
  --warna-bg-muted:   #f9fafb;

  --font-utama:   'Playfair Display', Georgia, serif;
  --font-tubuh:   'Source Serif Pro', Georgia, serif;
  --font-kode:    'Fira Code', 'Courier New', monospace;

  --font-xs:    0.75rem;    /* 12px */
  --font-sm:    0.875rem;   /* 14px */
  --font-base:  1rem;       /* 16px */
  --font-lg:    1.125rem;   /* 18px */
  --font-xl:    1.25rem;    /* 20px */
  --font-2xl:   1.5rem;     /* 24px */
  --font-3xl:   1.875rem;   /* 30px */
  --font-4xl:   2.25rem;    /* 36px */

  --spasi-1:  0.25rem;  /* 4px */
  --spasi-2:  0.5rem;   /* 8px */
  --spasi-3:  0.75rem;  /* 12px */
  --spasi-4:  1rem;     /* 16px */
  --spasi-6:  1.5rem;   /* 24px */
  --spasi-8:  2rem;     /* 32px */
  --spasi-12: 3rem;     /* 48px */
  --spasi-16: 4rem;     /* 64px */

  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   16px;
  --radius-bulat: 9999px;

  --bayangan-sm:  0 1px 3px rgba(0,0,0,0.12);
  --bayangan-md:  0 4px 12px rgba(0,0,0,0.15);
  --bayangan-lg:  0 10px 30px rgba(0,0,0,0.2);

  --transisi-cepat:  0.15s ease;
  --transisi-normal: 0.3s ease;
  --transisi-lambat: 0.5s ease;

  --lebar-maks: 1200px;
  --lebar-konten: 65ch;
}

/* ====================================================
   Menggunakan variabel dengan var()
   ==================================================== */
.tombol {
  background-color: var(--warna-primer);
  color: var(--warna-bg);
  padding: var(--spasi-3) var(--spasi-6);
  border-radius: var(--radius-md);
  font-family: var(--font-tubuh);
  font-size: var(--font-base);
  transition: background-color var(--transisi-cepat);
  box-shadow: var(--bayangan-sm);
}

/* var() menerima fallback value sebagai argumen kedua */
.elemen {
  color: var(--warna-kustom, #333);           /* pakai #333 jika --warna-kustom tidak ada */
  font-size: var(--font-kustom, var(--font-base)); /* fallback ke variabel lain */
}

/* ====================================================
   Variabel dapat di-override pada scope yang lebih spesifik
   ==================================================== */
.kartu-bahaya {
  --warna-primer: var(--warna-bahaya); /* override hanya dalam scope ini */
  background-color: var(--warna-primer);
}

/* ====================================================
   Dark mode dengan variabel CSS
   ==================================================== */
:root {
  --warna-teks: #1f2937;
  --warna-bg:   #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --warna-teks: #f9fafb;
    --warna-bg:   #111827;
  }
}

/* Atau dengan class di body */
body.tema-gelap {
  --warna-teks: #f9fafb;
  --warna-bg:   #111827;
  --warna-bg-muted: #1f2937;
}

/* ====================================================
   Variabel dalam calc()
   ==================================================== */
:root {
  --grid-kolom: 12;
  --grid-gap: 16px;
}

.kolom-6 {
  width: calc((100% / var(--grid-kolom)) * 6 - var(--grid-gap));
}

/* ====================================================
   Variabel bisa diubah dengan JavaScript
   ==================================================== */
/* JavaScript: */
/* document.documentElement.style.setProperty('--warna-primer', '#f00'); */

21. Pseudo-class

Pseudo-class memilih elemen berdasarkan kondisi atau state tertentu.

/* ====================================================
   State Interaksi
   ==================================================== */
a:link     { color: blue; }     /* link yang belum dikunjungi */
a:visited  { color: purple; }   /* link yang sudah dikunjungi */
a:hover    { color: red; }      /* saat mouse di atas elemen */
a:active   { color: darkred; }  /* saat elemen sedang diklik */
/* Urutan yang benar: LVHA */

button:focus        { outline: 2px solid blue; }   /* elemen mendapat fokus */
button:focus-within { outline: 2px solid blue; }   /* elemen atau anaknya fokus */
button:focus-visible { outline: 2px solid blue; }  /* fokus hanya via keyboard */

input:checked    { /* checkbox/radio yang dipilih */ }
input:disabled   { opacity: 0.5; cursor: not-allowed; }
input:enabled    { /* kebalikan disabled */ }
input:required   { border-color: red; }
input:optional   { /* input tanpa required */ }
input:valid      { border-color: green; }
input:invalid    { border-color: red; }
input:in-range   { /* nilai input dalam range min-max */ }
input:out-of-range { /* nilai di luar range */ }
input:placeholder-shown { /* saat placeholder terlihat (input masih kosong) */ }
input:read-only  { background: #eee; }
input:read-write { /* input yang bisa diedit */ }

/* ====================================================
   Struktural - berdasarkan posisi dalam DOM
   ==================================================== */
/* :first-child / :last-child */
li:first-child { font-weight: bold; }    /* anak pertama dari parent */
li:last-child  { border-bottom: none; } /* anak terakhir dari parent */

/* :nth-child() - memilih berdasarkan urutan */
/* Sintaks: :nth-child(An + B) */
li:nth-child(2)      { /* anak ke-2 */ }
li:nth-child(3n)     { /* setiap kelipatan 3: anak ke 3, 6, 9, ... */ }
li:nth-child(3n + 1) { /* anak ke 1, 4, 7, 10, ... */ }
li:nth-child(even)   { background: #f5f5f5; } /* genap: 2, 4, 6, ... */
li:nth-child(odd)    { /* ganjil: 1, 3, 5, ... */ }
li:nth-child(-n + 3) { /* tiga anak pertama: 3, 2, 1 */ }

/* :nth-last-child() - dihitung dari belakang */
li:nth-last-child(1) { /* anak terakhir (sama dengan :last-child) */ }
li:nth-last-child(2) { /* anak kedua dari belakang */ }

/* :first-of-type / :last-of-type */
/* Memilih elemen berdasarkan tipe (tag), bukan urutan mutlak sebagai anak */
p:first-of-type { /* p pertama di dalam parent-nya */ }

/* :nth-of-type() */
p:nth-of-type(2) { /* p kedua di dalam parent-nya */ }

/* :only-child - anak tunggal */
p:only-child { /* p yang merupakan satu-satunya anak parent-nya */ }

/* :only-of-type */
p:only-of-type { /* p yang merupakan satu-satunya elemen p di parent-nya */ }

/* :empty - elemen tanpa anak (termasuk teks) */
div:empty { display: none; }

/* :not() - negasi selektor */
li:not(:last-child)    { border-bottom: 1px solid #eee; } /* semua li KECUALI yang terakhir */
input:not([type="submit"]) { border: 1px solid #ccc; }
.tombol:not(.disabled)     { cursor: pointer; }

/* :is() - menggabungkan selektor dalam grup (lebih efisien) */
:is(h1, h2, h3, h4, h5, h6) { line-height: 1.2; }
:is(article, section, aside) p { margin-bottom: 1rem; }

/* :where() - seperti :is() tapi spesifisitasnya NOL */
:where(h1, h2, h3) { font-family: serif; }

/* :has() - parent selector (pemilihan berdasarkan anak) */
/* Memilih elemen yang MEMILIKI anak tertentu */
div:has(> p)          { /* div yang anak langsungnya ada p */ }
.kartu:has(img)       { /* .kartu yang di dalamnya ada img */ }
form:has(input:invalid) { border-color: red; }

/* ====================================================
   Lainnya
   ==================================================== */
:root { /* elemen root (biasanya html), spesifisitas lebih tinggi dari html */ }

p:lang(id) { /* elemen p dengan atribut lang="id" */ }

.target:target { /* elemen yang menjadi target URL hash (#target) */ }

@supports (display: grid) {
  /* Hanya dieksekusi jika browser mendukung property tersebut */
}

22. Pseudo-element

Pseudo-element membuat atau memilih bagian virtual dari elemen yang tidak ada di HTML.

/* ====================================================
   ::before dan ::after
   Membuat konten virtual sebelum/sesudah isi elemen
   WAJIB ada properti 'content' (bisa string kosong)
   ==================================================== */
.elemen::before {
  content: "";              /* wajib ada */
  content: "prefix - ";    /* menambahkan teks */
  content: url('ikon.svg'); /* menambahkan gambar */
  content: attr(data-label); /* menggunakan nilai atribut */
  content: counter(item);    /* counter CSS */

  /* ::before dan ::after bersifat inline by default */
  display: block;           /* biasanya diubah ke block atau flex */
}

/* Contoh: ikon bintang sebelum heading */
h2::before {
  content: "★ ";
  color: gold;
}

/* Contoh: badge */
.premium::after {
  content: "PRO";
  font-size: 0.6em;
  background: gold;
  color: #333;
  padding: 2px 6px;
  border-radius: 3px;
  margin-left: 6px;
  vertical-align: middle;
}

/* Contoh: overlay dengan ::before */
.hero {
  position: relative;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;                 /* shorthand untuk top:0 right:0 bottom:0 left:0 */
  background: rgba(0, 0, 0, 0.4);
  z-index: 1;
}

/* Contoh: garis dekoratif di bawah heading */
h2 {
  position: relative;
  display: inline-block;
}
h2::after {
  content: "";
  display: block;
  height: 3px;
  background: linear-gradient(to right, #3498db, transparent);
  margin-top: 6px;
  border-radius: 2px;
}

/* ====================================================
   ::first-line - memilih baris pertama teks
   ==================================================== */
p::first-line {
  font-weight: bold;
  font-size: 1.1em;
  color: #333;
  /* Hanya properti font, text, color, background yang berlaku */
}

/* ====================================================
   ::first-letter - memilih huruf pertama
   ==================================================== */
p::first-letter {
  font-size: 3.5em;
  font-weight: bold;
  float: left;            /* efek drop cap */
  line-height: 0.8;
  margin: 0.05em 0.1em 0 0;
  color: #c0392b;
  font-family: 'Georgia', serif;
}

/* ====================================================
   ::selection - style teks yang disorot user
   ==================================================== */
::selection {
  background-color: #3498db;
  color: white;
}

p::selection {
  background-color: rgba(255, 165, 0, 0.3);
}

/* ====================================================
   ::placeholder - style placeholder input
   ==================================================== */
input::placeholder {
  color: #9ca3af;
  font-style: italic;
  opacity: 1; /* Firefox mengurangi opacity by default */
}

/* ====================================================
   ::marker - style bullet/nomor list
   ==================================================== */
li::marker {
  color: #3498db;
  font-size: 1.2em;
  font-weight: bold;
  content: "→ "; /* ganti marker */
}

/* ====================================================
   ::backdrop - latar di belakang elemen dialog/fullscreen
   ==================================================== */
dialog::backdrop {
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(4px);
}

/* ====================================================
   ::cue - style subtitle/caption video
   ==================================================== */
::cue {
  background: rgba(0, 0, 0, 0.8);
  color: white;
  font-size: 0.9em;
}

/* ====================================================
   ::file-selector-button - tombol input file
   ==================================================== */
input[type="file"]::file-selector-button {
  background: #3498db;
  color: white;
  border: none;
  padding: 6px 12px;
  border-radius: 4px;
  cursor: pointer;
}

23. Media Query dan Responsive Design

Media query memungkinkan kita menerapkan CSS yang berbeda berdasarkan karakteristik perangkat.

23.1 Sintaks Media Query

/* Sintaks dasar */
@media media-type and (kondisi) {
  /* CSS yang diterapkan jika kondisi terpenuhi */
}

/* Media types */
@media screen { /* monitor dan layar */ }
@media print  { /* saat halaman dicetak */ }
@media all    { /* semua media (default) */ }

/* Feature queries (kondisi) */
@media (max-width: 768px)   { /* layar dengan lebar maksimal 768px */ }
@media (min-width: 768px)   { /* layar dengan lebar minimal 768px */ }
@media (width: 768px)       { /* layar dengan lebar tepat 768px */ }

/* Menggabungkan kondisi */
@media (min-width: 768px) and (max-width: 1024px) { /* antara 768px dan 1024px */ }
@media (max-width: 600px) or (orientation: portrait) { /* salah satu kondisi terpenuhi */ }
@media not (max-width: 768px) { /* negasi kondisi */ }

/* Range syntax (modern, lebih intuitif) */
@media (width >= 768px) { /* sama dengan min-width */ }
@media (width <= 1024px) { /* sama dengan max-width */ }
@media (768px <= width <= 1024px) { /* range */  }

23.2 Breakpoint Umum

/* Mobile-first approach (DISARANKAN) */
/* Mulai dari layar kecil, tambahkan style untuk layar lebih besar */

/* Base styles: mobile (< 640px) */
.container {
  padding: 0 16px;
  width: 100%;
}

/* Small / tablet kecil (>= 640px) */
@media (min-width: 640px) {
  .container {
    padding: 0 24px;
  }
}

/* Medium / tablet (>= 768px) */
@media (min-width: 768px) {
  .container {
    max-width: 768px;
    margin: 0 auto;
    padding: 0 32px;
  }
}

/* Large / laptop (>= 1024px) */
@media (min-width: 1024px) {
  .container {
    max-width: 1024px;
  }
}

/* Extra large / desktop (>= 1280px) */
@media (min-width: 1280px) {
  .container {
    max-width: 1280px;
    padding: 0 40px;
  }
}

/* 2XL / layar besar (>= 1536px) */
@media (min-width: 1536px) {
  .container {
    max-width: 1400px;
  }
}

23.3 Fitur Media Query Lainnya

/* Orientasi perangkat */
@media (orientation: portrait)  { /* layar tinggi (vertikal) */ }
@media (orientation: landscape) { /* layar lebar (horizontal) */ }

/* Resolusi layar */
@media (min-resolution: 2dppx) { /* layar retina / HiDPI */ }
@media (-webkit-min-device-pixel-ratio: 2) { /* versi webkit */ }

/* Preferensi pengguna */
@media (prefers-color-scheme: dark)    { /* mode gelap */ }
@media (prefers-color-scheme: light)   { /* mode terang */ }
@media (prefers-reduced-motion: reduce) { /* preferensi gerak minim */ }
@media (prefers-contrast: more)         { /* preferensi kontras tinggi */ }
@media (prefers-reduced-data: reduce)   { /* hemat data */ }
@media (prefers-reduced-transparency: reduce) { /* kurangi transparansi */ }

/* Hover capability */
@media (hover: hover) { /* perangkat yang mendukung hover (mouse) */ }
@media (hover: none)  { /* perangkat tanpa hover (touch) */ }
@media (pointer: fine)   { /* pointer akurasi tinggi (mouse) */ }
@media (pointer: coarse) { /* pointer akurasi rendah (touch/stylus) */ }
@media (pointer: none)   { /* tidak ada pointer (keyboard only) */ }

/* Display mode (PWA) */
@media (display-mode: standalone) { /* app berjalan sebagai PWA */ }
@media (display-mode: browser)    { /* app berjalan di browser biasa */ }

23.4 Strategi Responsive

/* ====================================================
   Fluid Typography - ukuran font yang benar-benar fluid
   ==================================================== */
/* Menggunakan clamp(min, preferred, max) */
h1 {
  font-size: clamp(1.75rem, 4vw, 3rem);
  /* minimum 1.75rem, ideal 4vw, maksimum 3rem */
  /* berubah halus sesuai lebar viewport, tanpa media query! */
}

p {
  font-size: clamp(1rem, 1.5vw, 1.25rem);
}

/* ====================================================
   Fluid Spacing
   ==================================================== */
.section {
  padding: clamp(2rem, 8vw, 6rem) clamp(1rem, 5vw, 3rem);
}

/* ====================================================
   Responsive Images
   ==================================================== */
img {
  max-width: 100%;    /* gambar tidak melebihi lebar container */
  height: auto;       /* tinggi mengikuti proporsi */
  display: block;     /* menghapus whitespace di bawah gambar */
}

/* Gambar yang mengisi penuh container dengan rasio aspek tertentu */
.gambar-rasio {
  aspect-ratio: 16 / 9; /* lebar : tinggi */
  width: 100%;
  object-fit: cover;    /* gambar mengisi area tanpa distorsi */
  object-position: center; /* posisi fokus gambar */
}

/* aspect-ratio values: 
   aspect-ratio: 1;        /* persegi */
   aspect-ratio: 4 / 3;
   aspect-ratio: 16 / 9;
   aspect-ratio: auto;     /* ikuti dimensi asli */

/* ====================================================
   Container Queries (sangat modern)
   Responsif berdasarkan ukuran CONTAINER, bukan viewport
   ==================================================== */
.wrapper {
  container-type: inline-size; /* aktifkan container query */
  container-name: kartu-wrapper; /* beri nama (opsional) */
}

/* Atau shorthand */
.wrapper {
  container: kartu-wrapper / inline-size;
}

@container kartu-wrapper (min-width: 400px) {
  .kartu {
    flex-direction: row; /* layout berubah saat container cukup lebar */
  }
}

/* Container query tanpa nama (berlaku untuk container terdekat) */
@container (min-width: 300px) {
  .konten-kartu {
    font-size: 1.1rem;
  }
}

24. Filter dan Efek Visual

24.1 Filter

.elemen {
  /* filter diterapkan pada elemen beserta kontennya */

  filter: blur(4px);              /* efek buram */
  filter: brightness(1.5);        /* kecerahan: 0=hitam, 1=normal, 2=sangat terang */
  filter: contrast(1.5);          /* kontras: 0=abu, 1=normal, 2=sangat kontras */
  filter: grayscale(1);           /* hitam putih: 0=normal, 1=sepenuhnya B&W */
  filter: grayscale(50%);         /* setengah hitam putih */
  filter: saturate(2);            /* saturasi: 0=B&W, 1=normal, 2=oversaturated */
  filter: hue-rotate(90deg);      /* geser hue warna */
  filter: invert(1);              /* balik warna: 0=normal, 1=sepenuhnya dibalik */
  filter: opacity(0.5);           /* transparansi (sama dengan properti opacity) */
  filter: sepia(1);               /* efek foto tua */
  filter: drop-shadow(4px 4px 8px rgba(0,0,0,0.3)); /* bayangan mengikuti bentuk asli */

  /* Menggabungkan filter */
  filter: brightness(1.1) contrast(1.05) saturate(1.2);
  filter: grayscale(1) blur(2px);

  /* backdrop-filter: filter pada latar belakang di belakang elemen */
  /* Berguna untuk efek glass/frosted */
  backdrop-filter: blur(10px);
  backdrop-filter: blur(10px) brightness(0.8);
  backdrop-filter: saturate(1.8) blur(4px);
  /* Elemen harus memiliki background yang tidak sepenuhnya opak */
  background: rgba(255, 255, 255, 0.2);
}

/* Contoh: efek kartu frosted glass */
.glass-card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(12px) saturate(1.5);
  -webkit-backdrop-filter: blur(12px) saturate(1.5);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
}

24.2 Mix Blend Mode dan Isolation

.elemen {
  /* mix-blend-mode: cara elemen ini berpadu dengan layer di bawahnya */
  mix-blend-mode: normal;      /* default */
  mix-blend-mode: multiply;    /* dikali: mempergelap */
  mix-blend-mode: screen;      /* seperti proyektor: mencerahkan */
  mix-blend-mode: overlay;     /* campuran multiply dan screen */
  mix-blend-mode: darken;      /* ambil warna yang lebih gelap */
  mix-blend-mode: lighten;     /* ambil warna yang lebih terang */
  mix-blend-mode: color-dodge; /* mencerahkan berdasarkan warna atas */
  mix-blend-mode: color-burn;  /* mempergelap berdasarkan warna atas */
  mix-blend-mode: hard-light;
  mix-blend-mode: soft-light;
  mix-blend-mode: difference;  /* perbedaan warna (negatif) */
  mix-blend-mode: exclusion;
  mix-blend-mode: hue;
  mix-blend-mode: saturation;
  mix-blend-mode: color;
  mix-blend-mode: luminosity;

  /* background-blend-mode: memadukan lapisan background dengan background-color */
  background-blend-mode: multiply;
}

/* isolation: membuat stacking context baru, mencegah mix-blend-mode melampaui elemen ini */
.container {
  isolation: isolate; /* atau: auto */
}

24.3 Clip Path dan Shape

.elemen {
  /* clip-path: memotong elemen menjadi bentuk tertentu */

  /* inset(): persegi panjang dengan rounding opsional */
  clip-path: inset(10px);                    /* dari semua sisi */
  clip-path: inset(10px 20px);              /* atas-bawah | kiri-kanan */
  clip-path: inset(10px round 10px);         /* dengan border radius */

  /* circle(): lingkaran */
  clip-path: circle(50%);                   /* lingkaran setengah ukuran elemen */
  clip-path: circle(100px at center);        /* lingkaran 100px di tengah */
  clip-path: circle(80px at 30% 50%);

  /* ellipse(): elips */
  clip-path: ellipse(100px 60px at center);

  /* polygon(): poligon dengan koordinat titik-titik */
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%); /* segitiga */
  clip-path: polygon(
    0 0,                /* titik kiri atas */
    100% 0,            /* titik kanan atas */
    100% 80%,          /* titik kanan bawah dengan indent */
    0 100%             /* titik kiri bawah */
  );
  /* Efek diagonal section */

  /* path(): bentuk custom menggunakan SVG path */
  clip-path: path('M 0 0 L 100 0 L 50 100 Z');

  /* Animasi clip-path */
  clip-path: circle(0%);
  transition: clip-path 0.5s ease;
}
.elemen:hover {
  clip-path: circle(100%); /* efek reveal lingkaran saat hover */
}

/* shape-outside: membuat teks mengalir mengikuti bentuk float */
.gambar-float {
  float: left;
  width: 200px;
  shape-outside: circle(50%);
  clip-path: circle(50%);
  margin: 10px 20px 10px 0;
}

25. CSS Functions

CSS memiliki banyak fungsi bawaan yang sangat powerful.

.elemen {
  /* ====================================================
     Fungsi Matematika
     ==================================================== */
  width: calc(100% - 40px);          /* kalkulasi campuran satuan */
  width: calc(50% + 20px);
  padding: calc(var(--spasi-4) * 1.5);
  font-size: calc(1rem + 0.5vw);

  /* min() - nilai terkecil dari argumen */
  width: min(90%, 600px);          /* 90% ATAU 600px, ambil yang lebih kecil */
  font-size: min(4vw, 2rem);

  /* max() - nilai terbesar dari argumen */
  width: max(200px, 50%);          /* 200px ATAU 50%, ambil yang lebih besar */
  padding: max(16px, 2vw);

  /* clamp(min, preferred, max) */
  font-size: clamp(1rem, 2.5vw, 2rem);
  width: clamp(200px, 50%, 800px);
  margin: clamp(1rem, 5vw, 3rem) auto;

  /* round() - membulatkan nilai (CSS Values 5) */
  font-size: round(1.234rem, 0.1rem); /* 1.2rem */

  /* mod() - modulus */
  /* rem() - remainder */
  /* sin(), cos(), tan(), asin(), acos(), atan(), atan2() - trigonometri */
  /* pow(), sqrt(), log(), exp() - matematika lanjutan */
  /* abs() - nilai absolut */
  /* sign() - tanda nilai */

  /* ====================================================
     Fungsi Warna
     ==================================================== */
  color: rgb(255, 100, 0);
  color: rgba(255, 100, 0, 0.5);
  color: hsl(30, 100%, 50%);
  color: hsla(30, 100%, 50%, 0.8);
  color: oklch(0.7 0.15 30);

  /* color-mix() - mencampur dua warna */
  color: color-mix(in srgb, red 50%, blue); /* campuran merah dan biru */
  color: color-mix(in hsl, red 30%, blue);
  color: color-mix(in oklch, #ff0000 25%, #0000ff);

  /* ====================================================
     Fungsi Gradient
     ==================================================== */
  background: linear-gradient(45deg, red, blue);
  background: radial-gradient(circle, red, blue);
  background: conic-gradient(red, blue, red);
  background: repeating-linear-gradient(45deg, red 0, red 10px, white 10px, white 20px);

  /* ====================================================
     Fungsi Shape (untuk clip-path, shape-outside)
     ==================================================== */
  clip-path: circle(50%);
  clip-path: ellipse(100px 60px at center);
  clip-path: inset(10px round 5px);
  clip-path: polygon(0 0, 100% 0, 50% 100%);

  /* ====================================================
     Fungsi Transform
     ==================================================== */
  transform: translate(10px, 20px);
  transform: rotate(45deg);
  transform: scale(1.5);
  transform: skew(10deg, 5deg);
  transform: matrix(1, 0, 0, 1, 10, 20);
  transform: perspective(800px) rotateY(45deg);

  /* ====================================================
     Fungsi Filter
     ==================================================== */
  filter: blur(4px);
  filter: brightness(1.5) contrast(1.2);
  filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));

  /* ====================================================
     Fungsi Lainnya
     ==================================================== */
  content: attr(data-label);      /* menggunakan nilai atribut HTML */
  content: counter(section);      /* nilai counter */
  font-family: var(--font-utama); /* menggunakan CSS variable */

  /* env() - nilai dari environment (OS/browser) */
  padding-top: env(safe-area-inset-top);    /* safe area untuk notch iPhone */
  padding-bottom: env(safe-area-inset-bottom);

  /* url() */
  background-image: url('gambar.jpg');
  list-style-image: url('bullet.svg');
}

/* @supports - feature detection di CSS */
@supports (display: grid) {
  .container { display: grid; }
}

@supports not (backdrop-filter: blur(1px)) {
  .glass { background: rgba(255, 255, 255, 0.9); } /* fallback */
}

@supports (color: oklch(0 0 0)) {
  :root { --warna-primer: oklch(0.55 0.2 250); }
}

26. Z-index dan Stacking Context

.elemen {
  /* z-index hanya berlaku pada elemen yang ber-position (bukan static) */
  /* atau pada flex/grid item */
  position: relative;
  z-index: 1;     /* angka lebih besar = lebih di depan */
  z-index: -1;    /* di belakang parent */
  z-index: auto;  /* tidak membuat stacking context baru */

  /* Stacking order dalam satu stacking context (dari belakang ke depan): */
  /* 1. Background dan border dari stacking context root */
  /* 2. Elemen dengan z-index negatif */
  /* 3. Block boxes (non-positioned) */
  /* 4. Float elements */
  /* 5. Inline boxes */
  /* 6. Positioned elements dengan z-index: auto atau 0 */
  /* 7. Positioned elements dengan z-index positif */
}

/* Hal-hal yang MEMBUAT stacking context baru: */
/* - position relative/absolute/fixed/sticky + z-index bukan auto */
/* - opacity < 1 */
/* - transform, filter, perspective, clip-path (nilai bukan none) */
/* - isolation: isolate */
/* - mix-blend-mode (nilai bukan normal) */
/* - will-change */
/* - contain: paint atau strict atau content */
/* - display: flex/grid pada parent (membuat flex/grid item menjadi stacking context jika z-index bukan auto) */

/* Pola z-index yang terorganisir */
:root {
  --z-dalam:     -1;
  --z-dasar:      0;
  --z-naik:      10;
  --z-dropdown: 100;
  --z-sticky:   200;
  --z-overlay:  300;
  --z-modal:    400;
  --z-toast:    500;
  --z-tooltip:  600;
}

27. Outline, Shadow, dan Efek Lainnya

27.1 Box Shadow

.elemen {
  /* box-shadow: horizontal vertical blur spread color */
  /* spread: ukuran bayangan (bisa negatif) */
  box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.2);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  box-shadow: 0 0 0 3px blue; /* ring/outline dari luar */

  /* inset: bayangan ke dalam */
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.2);

  /* Multiple shadows (dipisah koma) */
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.12),
    0 4px 12px rgba(0, 0, 0, 0.1),
    0 16px 40px rgba(0, 0, 0, 0.08);

  /* Contoh layered shadow yang terlihat natural */
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.07),
    0 2px 4px rgba(0, 0, 0, 0.07),
    0 4px 8px rgba(0, 0, 0, 0.07),
    0 8px 16px rgba(0, 0, 0, 0.07),
    0 16px 32px rgba(0, 0, 0, 0.07);

  /* Contoh colored shadow */
  box-shadow: 0 8px 24px rgba(52, 152, 219, 0.4);
}

27.2 Properti Lainnya yang Berguna

.elemen {
  /* resize: apakah elemen bisa diubah ukurannya oleh user */
  /* Membutuhkan overflow bukan visible */
  resize: none;         /* tidak bisa diubah */
  resize: both;         /* horizontal dan vertikal */
  resize: horizontal;   /* hanya horizontal */
  resize: vertical;     /* hanya vertikal */
  overflow: auto;       /* wajib untuk resize */

  /* user-select: apakah teks bisa diseleksi user */
  user-select: auto;    /* default */
  user-select: none;    /* tidak bisa diseleksi */
  user-select: text;    /* bisa diseleksi */
  user-select: all;     /* klik sekali pilih semua */

  /* appearance: menghapus style bawaan browser untuk elemen form */
  appearance: none;     /* berguna untuk kustomisasi select, checkbox, dll */

  /* caret-color: warna kursor teks di input */
  caret-color: #3498db;
  caret-color: transparent; /* sembunyikan kursor */

  /* accent-color: warna aksen untuk elemen form bawaan browser */
  accent-color: #3498db; /* checkbox, radio, range, progress */

  /* pointer-events: apakah elemen bisa menerima event pointer/mouse */
  pointer-events: auto;  /* default */
  pointer-events: none;  /* menembus klik ke elemen di bawahnya */

  /* will-change: memberi tahu browser properti yang akan berubah */
  /* Gunakan hanya jika perlu, karena memakan memori */
  will-change: transform;   /* optimalkan untuk transformasi */
  will-change: opacity;
  will-change: auto;        /* hilangkan hint setelah animasi selesai */

  /* contain: batasi scope rendering untuk performa */
  contain: strict;    /* paint, layout, size, style */
  contain: content;   /* paint, layout, style */
  contain: paint;     /* konten tidak terlihat di luar batas */
  contain: layout;    /* layout internal tidak mempengaruhi luar */

  /* content-visibility: optimization rendering */
  content-visibility: auto;     /* lewati rendering jika di luar viewport */
  contain-intrinsic-size: 0 300px; /* perkiraan ukuran untuk scroll */
}

28. Cursor dan Pointer Events

.elemen {
  /* cursor: tampilan kursor mouse saat berada di atas elemen */
  cursor: auto;           /* kursor default browser */
  cursor: default;        /* panah normal */
  cursor: pointer;        /* jari telunjuk (untuk tombol, link) */
  cursor: text;           /* kursor I-beam (untuk teks yang bisa diedit) */
  cursor: crosshair;      /* tanda plus */
  cursor: move;           /* empat panah (untuk element yang bisa dipindah) */
  cursor: grab;           /* tangan terbuka */
  cursor: grabbing;       /* tangan menggenggam */
  cursor: not-allowed;    /* lingkaran dengan garis (aksi tidak diizinkan) */
  cursor: wait;           /* jam / loading */
  cursor: progress;       /* loading tapi masih bisa interaksi */
  cursor: help;           /* tanda tanya */
  cursor: zoom-in;        /* kaca pembesar + */
  cursor: zoom-out;       /* kaca pembesar - */
  cursor: copy;           /* tanda copy */
  cursor: alias;          /* tanda alias/shortcut */
  cursor: cell;           /* salib tebal */
  cursor: col-resize;     /* panah kiri-kanan untuk resize kolom */
  cursor: row-resize;     /* panah atas-bawah untuk resize baris */
  cursor: none;           /* sembunyikan kursor sepenuhnya */

  /* Cursor custom */
  cursor: url('kursor.cur'), auto; /* cursor custom dengan fallback */
  cursor: url('kursor.svg') 16 16, pointer;
  /* Angka 16 16 adalah hotspot (titik aktif) cursor */
}

29. Scroll Behavior

html {
  scroll-behavior: smooth; /* scroll halus untuk anchor link */
}

/* Scroll snapping */
.galeri {
  display: flex;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
  gap: 16px;
  padding: 16px;

  /* Menyembunyikan scrollbar tapi tetap bisa scroll */
  scrollbar-width: none;         /* Firefox */
  -ms-overflow-style: none;      /* IE/Edge lama */
}

.galeri::-webkit-scrollbar {
  display: none;                 /* Chrome, Safari */
}

.slide {
  flex: 0 0 100%;                /* setiap slide selebar container */
  scroll-snap-align: start;      /* snap di tepi kiri setiap slide */
}

/* Kustomisasi scrollbar */
.konten::-webkit-scrollbar {
  width: 8px;                    /* lebar scrollbar vertikal */
  height: 8px;                   /* tinggi scrollbar horizontal */
}

.konten::-webkit-scrollbar-track {
  background: #f1f1f1;           /* trek scrollbar */
  border-radius: 4px;
}

.konten::-webkit-scrollbar-thumb {
  background: #888;              /* tombol scrollbar */
  border-radius: 4px;
}

.konten::-webkit-scrollbar-thumb:hover {
  background: #555;
}

/* Firefox scrollbar */
.konten {
  scrollbar-width: thin;         /* auto, thin, none */
  scrollbar-color: #888 #f1f1f1; /* thumb track */
}

/* scroll-padding: offset saat scroll ke anchor */
/* Berguna untuk kompensasi fixed header */
html {
  scroll-padding-top: 80px;      /* tinggi header */
}

/* overscroll-behavior: kontrol efek bounce scroll */
.modal {
  overflow-y: auto;
  overscroll-behavior: contain;  /* scroll tidak menerus ke elemen induk */
  overscroll-behavior-y: none;   /* tidak ada efek bounce vertikal */
}

30. Best Practice dan Metodologi CSS

30.1 Reset dan Normalize

/* CSS Reset - menghapus semua style bawaan browser */
/* Pendekatan modern (Andy Bell's Modern CSS Reset) */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  hanging-punctuation: first last;
}

body {
  min-height: 100vh;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased; /* rendering font lebih halus di Mac */
  text-rendering: optimizeSpeed;
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit; /* form elements mewarisi font dari parent */
}

p,
h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word; /* cegah overflow teks panjang */
}

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance; /* buat baris heading lebih seimbang */
}

p {
  text-wrap: pretty; /* hindari orphan (kata sendirian di baris terakhir) */
}

30.2 Metodologi CSS

/* ====================================================
   BEM (Block Element Modifier)
   Penamaan: block__element--modifier
   ==================================================== */

/* Block: komponen independen */
.kartu { /* ... */ }

/* Element: bagian dari block */
.kartu__gambar { /* ... */ }
.kartu__judul  { /* ... */ }
.kartu__body   { /* ... */ }
.kartu__footer { /* ... */ }

/* Modifier: variasi dari block atau element */
.kartu--featured     { /* ... */ } /* kartu yang ditonjolkan */
.kartu--horizontal   { /* ... */ } /* kartu layout horizontal */
.kartu__judul--besar { /* ... */ } /* judul yang lebih besar */

/* HTML:
<article class="kartu kartu--featured">
  <img class="kartu__gambar" ...>
  <h2 class="kartu__judul kartu__judul--besar">Judul</h2>
  <div class="kartu__body">Konten</div>
</article>
*/

/* ====================================================
   Utility-First (seperti Tailwind CSS)
   ==================================================== */
.flex { display: flex; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.p-4 { padding: 1rem; }
.text-xl { font-size: 1.25rem; }
.font-bold { font-weight: bold; }
.rounded-lg { border-radius: 0.5rem; }
.bg-blue-500 { background-color: #3b82f6; }

/* ====================================================
   OOCSS (Object-Oriented CSS)
   Pisahkan struktur dari visual
   ==================================================== */
/* Struktur (tidak ada warna/visual) */
.media {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}
.media__gambar { flex-shrink: 0; }
.media__body   { flex: 1; }

/* Visual (tidak ada layout/positioning) */
.tema-primer { background: #3498db; color: white; }
.tema-gelap  { background: #2c3e50; color: white; }

30.3 Tips Performa CSS

/* ====================================================
   1. Hindari selector yang terlalu panjang dan spesifik
   ==================================================== */
/* BURUK - terlalu spesifik, sulit di-override, lambat */
div#container > ul.daftar > li.item > a.link:hover { color: red; }

/* BAIK - sederhana dan langsung */
.daftar-link:hover { color: red; }

/* ====================================================
   2. Hindari selektor universal yang berlebihan
   ==================================================== */
/* BURUK */
* { margin: 0; padding: 0; } /* meski OK untuk reset, jangan gunakan di komponen */

/* BAIK */
.container > * { margin-bottom: 1rem; } /* batasi scope */

/* ====================================================
   3. Gunakan shorthand tapi tetap eksplisit jika perlu
   ==================================================== */
/* Shorthand bisa secara tidak sengaja mereset properti yang tidak ingin direset */
/* HATI-HATI: */
background: red; /* ini juga mereset background-image, size, dll! */

/* Lebih aman */
background-color: red;

/* ====================================================
   4. Preferensikan transform dan opacity untuk animasi
   Keduanya diproses di GPU, tidak trigger layout/paint
   ==================================================== */
/* BURUK untuk animasi (trigger layout/paint) */
.animasi-buruk:hover {
  width: 200px;     /* trigger layout */
  height: 200px;    /* trigger layout */
  top: 10px;        /* trigger layout */
  left: 20px;       /* trigger layout */
}

/* BAIK untuk animasi (hanya GPU compositing) */
.animasi-baik:hover {
  transform: scale(1.1) translate(10px, 5px);
  opacity: 0.9;
}

/* ====================================================
   5. Gunakan will-change dengan bijaksana
   ==================================================== */
.elemen-animasi {
  will-change: transform; /* HANYA saat animasi akan segera terjadi */
}
/* Hapus will-change setelah animasi selesai dengan JavaScript */

/* ====================================================
   6. Hindari @import di CSS untuk produksi (lebih lambat dari <link>)
   ==================================================== */
/* Gunakan di development untuk organisasi, tapi bundling untuk produksi */

/* ====================================================
   7. Organisasi file CSS
   ==================================================== */

/*
   Struktur file yang disarankan:
   
   styles/
   ├── base/
   │   ├── reset.css
   │   ├── typography.css
   │   └── variables.css
   ├── components/
   │   ├── button.css
   │   ├── card.css
   │   ├── navbar.css
   │   └── modal.css
   ├── layout/
   │   ├── grid.css
   │   ├── container.css
   │   └── sidebar.css
   ├── pages/
   │   ├── home.css
   │   └── about.css
   ├── utilities/
   │   ├── spacing.css
   │   ├── typography.css
   │   └── colors.css
   └── main.css (mengimpor semua)
*/

30.4 CSS Modern yang Perlu Diketahui

/* ====================================================
   Logical Properties - layout yang sadar arah teks (RTL/LTR)
   ==================================================== */
.elemen {
  /* Pengganti margin-left/right, padding-top/bottom */
  margin-inline-start: 1rem;   /* kiri untuk LTR, kanan untuk RTL */
  margin-inline-end: 1rem;     /* kanan untuk LTR, kiri untuk RTL */
  margin-block-start: 1rem;    /* atas untuk horizontal writing */
  margin-block-end: 1rem;      /* bawah untuk horizontal writing */

  /* Shorthand */
  margin-inline: 1rem;         /* start dan end sekaligus */
  margin-block: 2rem;          /* block-start dan block-end */
  padding-inline: 1rem 2rem;   /* start | end */

  /* Dimensi */
  inline-size: 300px;          /* lebar untuk LTR = width */
  block-size: 200px;           /* tinggi untuk horizontal = height */
  min-inline-size: 200px;
  max-block-size: 400px;

  /* Border dan posisi */
  border-inline-start: 2px solid blue;
  border-block-end: 1px solid gray;
  inset-inline-start: 0;       /* left untuk LTR */
  inset-block-start: 0;        /* top untuk horizontal */
  inset: 0;                    /* shorthand: top right bottom left semuanya 0 */
}

/* ====================================================
   Nesting CSS (Native, tanpa preprocessor)
   ==================================================== */
.kartu {
  background: white;
  padding: 1rem;

  /* Nesting langsung */
  .judul {
    font-size: 1.5rem;
    color: navy;
  }

  /* Nesting dengan & (referensi ke parent) */
  &:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  }

  &.aktif {
    border: 2px solid blue;
  }

  /* Nesting media query */
  @media (min-width: 768px) {
    padding: 2rem;
  }
}

/* ====================================================
   :has() untuk parent-based styling
   ==================================================== */
/* Kartu yang memiliki gambar mendapat padding lebih kecil */
.kartu:has(img) {
  padding-top: 0;
}

/* Form yang ada input invalid mendapat border merah */
form:has(input:invalid:not(:placeholder-shown)) {
  border-color: red;
}

/* Navigasi yang ada item aktif */
nav:has(.aktif) {
  background: rgba(0, 0, 255, 0.05);
}

/* ====================================================
   @layer - mengontrol urutan cascade
   ==================================================== */
/* Mendefinisikan urutan layer (prioritas dari rendah ke tinggi) */
@layer reset, base, komponen, utilitas;

@layer reset {
  * { margin: 0; padding: 0; }
}

@layer base {
  body { font-family: sans-serif; }
}

@layer komponen {
  .tombol { background: blue; }
}

@layer utilitas {
  .m-0 { margin: 0 !important; } /* !important dalam layer lebih lemah dari normal di luar layer */
}

Referensi Cepat: Perbedaan Flexbox vs Grid

Aspek Flexbox Grid
Dimensi Satu dimensi (baris ATAU kolom) Dua dimensi (baris DAN kolom)
Kontrol Dari anak (item menentukan ukurannya) Dari induk (container menentukan struktur)
Kegunaan terbaik Komponen UI, navigasi, alignment Layout halaman, galeri, template
Ukuran item Fleksibel berdasarkan konten Bisa didefinisikan tepat di grid
Overlap item Tidak mudah Mudah dengan grid-area
Responsive Sangat mudah dengan flex-wrap Sangat powerful dengan auto-fit/minmax
Browser support Sangat luas Sangat luas (IE11 parsial)
Kapan pakai Satu baris/kolom komponen Layout halaman keseluruhan

Referensi Cepat: Properti yang Paling Sering Digunakan

Properti Kegunaan
display: flex Aktifkan flexbox
display: grid Aktifkan grid
position: relative/absolute/fixed/sticky Kontrol positioning
box-sizing: border-box Kalkulasi ukuran yang wajar
margin: 0 auto Pusatkan elemen horizontal
width/max-width Kontrol lebar elemen
padding/margin Ruang dalam dan luar elemen
color/background-color Warna teks dan background
font-size/font-weight/font-family Tipografi
border-radius Sudut membulat
box-shadow Bayangan elemen
transition Animasi halus saat state berubah
transform Translasi, rotasi, skala
opacity Transparansi elemen
z-index Urutan tumpukan elemen
overflow: hidden Sembunyikan konten yang meluap
cursor: pointer Tunjukkan elemen bisa diklik
gap Jarak antar flex/grid item
clamp() Nilai fluid responsif
var() Gunakan CSS variable

Dokumentasi ini mencakup CSS dari versi dasar hingga fitur modern (CSS 2024). Selalu verifikasi dukungan browser di caniuse.com sebelum menggunakan fitur eksperimental di produksi.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors