Mengapa Aturan CSS Saya Tidak Bekerja?
Pernahkah Anda menulis color: blue; pada sebuah kelas CSS, tetapi teks di layar tetap berwarna abu-abu meskipun berkas CSS sudah dimuat dengan benar?
Di CSS, satu elemen HTML bisa menjadi target dari lima atau sepuluh aturan CSS yang berbeda secara bersamaan. Karena sebuah elemen hanya bisa memiliki satu nilai akhir untuk setiap properti (misalnya satu color dan satu font-size), peramban menjalankan algoritma resolusi konflik yang disebut The Cascade (Kaskade).
1. Urutan Prioritas Algoritma Cascade Modern
Ketika dua atau lebih deklarasi CSS memperebutkan properti yang sama pada satu elemen, peramban memutuskannya melalui tangga prioritas berikut (dari penentu tertinggi ke terendah):
1. Origin & Importance (!important)
(Transisi aktif > !important User Agent > !important User > !important Author > Normal Author > User > User Agent)
│
▼ (Jika sama-sama aturan Author normal:)
2. Konteks Enkapsulasi (mis. Shadow DOM vs dokumen luar)
│
▼
3. Atribut style="" Inline pada Elemen HTML
│
▼
4. Cascade Layers (@layer) — Lapisan yang dideklarasikan belakangan menang
(Aturan di luar @layer mengalahkan semua aturan normal di dalam @layer!)
│
▼ (Jika berada di dalam @layer yang sama:)
5. Spesifisitas Selektor (A, B, C) — ID > Class/Atribut/Pseudo-class > Elemen/Pseudo-element
│
▼ (Jika nilai spesifisitasnya seri/sama persis:)
6. Urutan Kemunculan (Order of Appearance) — Yang ditulis paling bawah menang!
2. Menghitung Spesifisitas Selektor (A, B, C)
Setiap selektor CSS memiliki skor spesifisitas yang terdiri dari tiga kolom: (A, B, C):
- Kolom
A(ID): Jumlah selektor ID (seperti#header). - Kolom
B(Kelas, Atribut, Pseudo-class): Jumlah.kelas,[atribut], dan:pseudo-class(seperti:hover,:focus-visible,:nth-child()). - Kolom
C(Tipe Elemen & Pseudo-element): Jumlah nama tag (div,p,a) dan::pseudo-element(::before,::after).
Aturan Penting Perhitungan:
- Kolom dibaca dari kiri ke kanan layaknya medali Olimpiade (Emas
A, PerakB, PerungguC). Satu medali Emas(1, 0, 0)selalu mengalahkan seribu medali Perak(0, 1000, 0)! - Selektor universal (
*), kombinator (>,+,~, spasi), dan pseudo-class:where(...)menyumbang(0, 0, 0). - Pseudo-class
:is(),:not(), dan:has()tidak dihitung sebagai dirinya sendiri, melainkan menyumbang spesifisitas tertinggi dari argumen di dalam kurungnya.
Tabel Contoh Perhitungan Spesifisitas
| Selektor | Skor (A, B, C) | Penjelasan Rincian |
|---|---|---|
* atau :where(#id.kelas) | (0, 0, 0) | Selektor universal dan :where() selalu bernilai nol. |
article | (0, 0, 1) | 1 elemen (article). |
article h2::before | (0, 0, 3) | 2 elemen (article, h2) + 1 pseudo-element (::before). |
.kartu | (0, 1, 0) | 1 kelas (.kartu) — mengalahkan article h2::before! |
ul.menu > li:first-child a[href] | (0, 3, 3) | 3 di kolom B (.menu, :first-child, [href]) dan 3 di kolom C (ul, li, a). |
:is(#konten, .biasa) p | (1, 0, 1) | :is() mengambil argumen tertinggi (#konten = 1,0,0) + p (0,0,1). |
#navigasi | (1, 0, 0) | 1 ID (#navigasi) — mengalahkan (0, 3, 3)! |
3. Mengendalikan Kaskade Tanpa Perang Spesifisitas dengan @layer
Dalam proyek besar yang menggabungkan CSS reset, pustaka komponen pihak ketiga, gaya dasar, dan kelas utilitas, pengembang sering terjebak dalam "perang spesifisitas"—menambahkan #id .bungkus .kartu .tombol atau menebar !important hanya demi menimpa gaya komponen bawaan.
Sejak Maret 2022 (status Baseline Widely Available), CSS menyediakan Cascade Layers (@layer) yang memungkinkan Anda menentukan urutan prioritas kelompok CSS secara eksplisit tanpa memedulikan spesifisitas selektor di antar-lapisan:
/* 1. Deklarasikan urutan lapisan di baris paling atas berkas CSS Anda
(dari prioritas TERENDAH di kiri ke TERTINGGI di kanan) */
@layer reset, dasar, komponen, utilitas;
@layer reset {
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
}
}
@layer komponen {
/* Meskipun selektor ini sangat spesifik (0, 2, 1), ia berada di layer 'komponen' */
.kartu-produk a.tombol-beli {
background-color: #2563eb;
color: #ffffff;
padding: 0.5rem 1rem;
}
}
@layer utilitas {
/* Selektor sederhana (0, 1, 0) ini MENANG melawan .kartu-produk a.tombol-beli
karena layer 'utilitas' berada setelah layer 'komponen'! */
.latar-merah {
background-color: #dc2626;
}
}
@layerAturan CSS normal yang ditulis tanpa @layer (unlayered styles) memiliki prioritas lebih tinggi daripada semua lapisan @layer. Oleh karena itu, jika Anda menggunakan @layer, masukkan seluruh aturan CSS proyek Anda ke dalam lapisan yang sesuai, atau gunakan lapisan untuk menampung kode reset dan pustaka pihak ketiga agar kode Anda selalu mudah menimpanya.
4. Pewarisan (Inheritance) dan Kata Kunci Pengendali Nilai
Tidak semua properti CSS diwariskan dari elemen induk ke elemen anak. Secara logis:
- **Properti yang otomatis diwariskan (Inherited):** Properti yang berkaitan dengan teks dan tipografi, seperti
color,font-family,font-size,font-weight,line-height,text-align,list-style, dan variabel CSS (--*). Jika Anda mengaturfont-familypada<body>, seluruh paragraf dan judul di dalamnya otomatis mewarisi fon tersebut. - **Properti yang TIDAK diwariskan (Non-inherited):** Properti yang berkaitan dengan kotak tata letak, seperti
width,height,margin,padding,border,background-color, dandisplay. (Bayangkan betapa kacaunya jika Anda memberiborder: 2px solid blackpada<body>lalu setiap<p>,<span>, dan<strong>di dalamnya ikut memiliki bingkai hitam sendiri!).
Namun, elemen formulir (<button>, <input>, <select>, <textarea>) secara bawaan tidak mewarisi font-family dan font-size dari <body> karena mengikuti gaya sistem operasi. Kita dapat memaksanya mewarisi fon induk menggunakan kata kunci inherit:
/* Memaksa elemen formulir mewarisi tipografi dari dokumen */
input, button, textarea, select {
font: inherit;
color: inherit;
}
Empat Kata Kunci Reset Nilai di CSS
inherit: Mengambil nilai komputasi dari elemen induk langsungnya.initial: Mengembalikan properti ke nilai awal menurut spesifikasi resmi CSS (hati-hati:initialdaridisplaypada<div>bukanlahblock, melainkaninline!).revert: Mengembalikan properti ke gaya bawaan peramban (user-agent stylesheet), sehinggadisplay: revertpada<div>kembali menjadiblock.revert-layer: Mengembalikan nilai properti ke nilai yang ditetapkan pada@layersebelumnya!
Kesalahan Umum dan Cara Menghindarinya
- Menyalahgunakan
!importantuntuk jalan pintas:- Bahaya: Begitu Anda menulis
color: red !important;pada komponen dasar, satu-satunya cara menimpanya di kemudian hari adalah dengan menulis!importantlagi dengan spesifisitas lebih tinggi. Simpan!importanthanya untuk kelas utilitas aksesibilitas seperti.sembunyikan[hidden] { display: none !important; }.
- Bahaya: Begitu Anda menulis
- Menggunakan selektor
#iduntuk penataan gaya komponen:- Lebih Baik: Gunakan atribut
iddi HTML untuk jangkar URL (#bagian),<label for="...">, atau JavaScript, tetapi gunakan.kelasdi CSS agar spesifisitas tetap rendah dan mudah dikelola.
- Lebih Baik: Gunakan atribut
Latihan Praktik: Menata Arsitektur CSS dengan @layer
Buatlah berkas kaskade-layer.html dan layer.css yang mendemonstrasikan:
- Tiga lapisan
@layer reset, komponen, utilitas;. - Di dalam
@layer reset, pastikan semua elemeninputdanbuttonmewarisifont: inherit. - Di dalam
@layer komponen, buat aturan#kartu-utama .judul-kartuberwarna biru tua. - Di dalam
@layer utilitas, buat kelas.teks-hijauyang berhasil mengubah warna#kartu-utama .judul-kartumenjadi hijau tanpa memakai!importantdan tanpa menulis#kartu-utama.