Selama 20+ tahun, CSS tidak punya parent selector. Kamu bisa bilang "semua <p> di dalam <article>", tapi tidak bisa "article yang mengandung gambar". Sampai akhirnya :has() hadir.
/* Card yang punya gambar di dalamnya — beri border lebih tebal */
.card:has(img) {
border: 2px solid black;
}
/* Form di mana ada input invalid */
form:has(input:invalid) {
border-color: red;
}
/* Paragraf yang langsung diikuti gambar */
p:has(+ img) {
margin-bottom: 0;
}
Kombinasi dengan selector lain:
/* Label yang membungkus checkbox tercentang */
label:has(input:checked) {
background: #e0ffe0;
}
/* Article yang TIDAK punya heading */
article:not(:has(h1, h2)) {
outline: 2px dashed orange;
}
Kenapa ini besar? Banyak efek UI dinamis yang dulu butuh JavaScript sekarang cukup CSS murni — menangkap keadaan parent berdasarkan anak, siblings, atau form state.
Browser support: 2023+. Cek caniuse.com jika perlu menargetkan browser lama.
🎭 Analogi sehari-hari
Bayangin kamu pemilik kosan dan baru bisa kasih tarif tergantung isi kamarnya — selama 20 tahun cuma bisa "kasih harga sama buat semua kamar". Sekarang akhirnya bisa: "kamar yang ADA AC-nya tarif lebih mahal", "kamar yang gak punya jendela kasih diskon". Itu yang :has() kasih ke CSS — selama 2 dekade kamu cuma bisa style anak berdasar parent (.parent .child), sekarang bisa style PARENT berdasar isi anaknya. .card:has(img) = "kartu yang isinya ada gambar, kasih border tebal". Banyak hal yang dulu butuh JavaScript sekarang cukup CSS saja.
⚠️ Jebakan yang sering ditemui
- Tidak bisa nested
:has()rekursif di banyak browser — keep simple. - Performance — browser harus cek descendants tiap update. Selectors complex
:has()di list besar = slow. - Browser support 2023+ — kalau target IE/Safari lama, butuh fallback (JS class toggle).
- Combinator dalam
:has()powerful::has(+ img)= "diikuti gambar". - Spec evolving —
:has()"non-forgiving" (selector salah → seluruh rule gagal). Hati-hati typo. - Replace JS class hack — banyak
el.classList.add('has-children')jadi tidak perlu.
TL;DR: :has() = parent selector — style parent berdasar isi anaknya. .card:has(img), form:has(input:invalid), label:has(input:checked). Bisa kombinasi :not() dan combinator (:has(+ img)). Banyak efek UI yang dulu butuh JavaScript sekarang cukup CSS. Browser support 2023+. Awas performance kalau dipakai di list besar — browser cek descendants tiap update.