Selector biasa memilih dari luar ke dalam: .card img artinya "gambar yang ada di dalam card". :has() membalik arahnya: dia memilih elemen berdasarkan apa yang ada di dalamnya, misalnya "card yang di dalamnya ada gambar". Karena bisa memilih induk (parent) dari isinya, :has() sering dijuluki parent selector.
🧪 Tebakan cepat: bisa gak CSS saja, tanpa JavaScript, bikin tombol Kirim redup selama email yang diketik belum valid? Tebak dulu, jawabannya ada di bagian "Bereaksi ke isi form".
Pilih elemen dari isinya
<label class="kartu">
<input type="checkbox"> Kirimi saya promo
</label>
<style>
.kartu:has(input:checked) {
background: #e0ffe0;
}
</style>
.kartuadalah elemen yang diberi gaya. Background-nya jatuh ke.kartu, bukan ke checkbox.:has(...)adalah syaratnya: "yang di dalamnya ada ...".input:checkedadalah yang dicari di dalam: input yang sedang dicentang. Letaknya boleh di mana saja di dalam.kartu, gak harus anak langsung.
Hasilnya, centang kotaknya dan seluruh kartu jadi hijau muda. Lepas centangnya, kartunya balik polos.
Bandingkan dua selector ini:
.card imgmemberi gaya ke gambarnya..card:has(img)memberi gaya ke card yang punya gambar. Card tanpa gambar gak kena.
Bereaksi ke isi form
form:has(input:invalid) button {
opacity: 0.5;
}
input:invalid adalah input yang isinya belum memenuhi aturannya, misalnya type="email" yang diisi abc, atau input required yang masih kosong. Jadi form:has(input:invalid) memilih form yang di dalamnya ada minimal satu input yang belum valid, dan button sesudahnya memilih tombol di dalam form itu.
Jawaban tebakan: bisa. Selama ada isian yang salah, tombolnya redup. Begitu semuanya valid, aturannya gak berlaku lagi dan tombolnya normal.
Kebalikannya: :not(:has(...))
Bungkus dengan :not() buat memilih elemen yang gak punya sesuatu:
.keranjang:not(:has(li))::after {
content: "Keranjang masih kosong";
}
Keranjang yang gak berisi satu <li> pun menampilkan tulisan itu. Tambah satu barang, tulisannya hilang sendiri.
⚠️ Jebakan yang sering ketemu
- Salah sasaran.
.card:has(img) { border: 2px solid; }memberi border ke card. Kalau yang mau diubah gambarnya, pakai.card img. - Salah ketik di dalam
:has(). Satu selector yang gak valid di dalamnya bikin seluruh aturan diabaikan, tanpa pesan error. :has()di dalam:has(). Ini gak diizinkan, aturannya gak jalan. Tulis syaratnya dalam satu:has().
TL;DR: :has() memilih elemen berdasarkan isinya, makanya dijuluki parent selector. .card:has(img) memilih card yang punya gambar, label:has(input:checked) label yang checkbox-nya dicentang, form:has(input:invalid) form yang punya input belum valid. Bungkus dengan :not() buat kebalikannya. Banyak efek yang dulu butuh JavaScript sekarang cukup CSS.