:has() Selector (Parent Selector) — CSS

Selama 20+ tahun, CSS tidak punya parent selector. Kamu bisa bilang "semua di dalam ", tapi tidak bisa "article yang mengandung gambar". Sampai akhirnya…

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>

Hasilnya, centang kotaknya dan seluruh kartu jadi hijau muda. Lepas centangnya, kartunya balik polos.

Bandingkan dua selector ini:

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

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.

Yang akan kamu pelajari