Selector tunggal menunjuk elemen secara individual, padahal makna banyak elemen lahir dari posisinya di dalam dokumen: paragraf pembuka setelah judul, item daftar di dalam menu, atau catatan yang terbungkus kotak. Combinator merangkai beberapa simple selector menjadi satu selector kompleks dengan mengekspresikan hubungan keluarga di pohon DOM: leluhur–keturunan, induk–anak, dan saudara. CSS menyediakan empat combinator. Chapter ini membedah keempatnya pada satu struktur HTML yang sama agar perbedaannya terlihat jelas.

Descendant Combinator: Spasi #

Spasi di antara dua selector berarti keturunan: selector di kanan dicocokkan bila berada di dalam elemen selector kiri, berapa pun kedalamannya. Aturan .artikel p menunjuk semua p di dalam .artikel, termasuk yang terbungkus elemen perantara:

css
.artikel p {
  color: rgb(71, 85, 105);
}

Child Combinator: Tanda Lebih Besar Dari #

Tanda > mempersempit pencocokan ke anak langsung. Aturan .artikel > p menunjuk p yang menjadi anak langsung .artikel; p yang terbungkus div tidak ikut. Perbedaan ini penting ketika struktur tengah boleh berubah tetapi relasi induk–anak tidak:

css
.artikel > p {
  border-left: 3px solid rgb(14, 165, 233);
}

Sibling Combinators: Tanda + dan ~ #

Dua combinator terakhir membaca urutan saudara, yaitu elemen-elemen yang berinduk sama. Adjacent sibling + menunjuk elemen yang tepat berada setelah selector kiri, sedangkan general sibling ~ menunjuk semua saudara setelahnya:

css
h2 + p {
  font-weight: 700;
}

h2 ~ p {
  letter-spacing: 0.5px;
}

Aturan pertama membuat paragraf yang tepat mengikuti h2 tampil tebal. Aturan kedua memberi jarak huruf pada setiap paragraf yang mengikuti h2 — termasuk paragraf pembuka — tetapi tidak pada paragraf yang berada di dalam elemen lain.

Membedah Struktur Demo #

Demo chapter ini menyatukan keempat aturan di atas pada satu artikel dengan struktur berikut:

html index.html
<article class="artikel">
  <h2>Rangkuman Mingguan</h2>
  <p>Ringkasan langsung setelah judul.</p>
  <div class="kotak">
    <p>Catatan di dalam kotak, bukan anak langsung artikel.</p>
  </div>
  <p>Penutup yang tetap sejajar dengan judul.</p>
</article>
text
article.artikel
├── h2
├── p   (p1 — anak langsung)
├── div.kotak
│   └── p   (p2 — keturunan, bukan anak langsung)
└── p   (p3 — anak langsung)

Mari kita telaah aturan demo baris demi baris, beserta elemen yang terkena:

css
.artikel p {
  color: rgb(71, 85, 105);
}

.artikel > p {
  border-left: 3px solid rgb(14, 165, 233);
}

h2 + p {
  font-weight: 700;
}

h2 ~ p {
  letter-spacing: 0.5px;
}
  1. Baris 1 (.artikel p): descendant combinator mengenai p1, p2, dan p3 — ketiganya berwarna abu-abu kebiruan.
  2. Baris 5 (.artikel > p): child combinator hanya mengenai p1 dan p3; p2 terbungkus div sehingga lolos dari garis kiri biru.
  3. Baris 9 (h2 + p): adjacent sibling hanya mengenai p1, karena hanya p1 yang tepat mengikuti h2; p1 menjadi tebal.
  4. Baris 13 (h2 ~ p): general sibling mengenai p1 dan p3, dua saudara yang berada setelah h2; keduanya berjarak huruf 0.5px. p2 bukan saudara h2 karena induknya berbeda.

Hasil di Browser:

text
Ketiga paragraf tampil abu-abu kebiruan (color: rgb(71, 85, 105)).
p1 tampil tebal (font-weight: 700) dengan garis kiri 3px.
p2 di dalam div tidak tebal (font-weight: 400) dan tanpa garis kiri
(border-left-width: 0px).
p3 tidak tebal (font-weight: 400), bergaris kiri 3px, dan berjarak
huruf 0.5px (letter-spacing: 0.5px).

Demo pada chapter ini membawa tiga paragraf uji dengan atribut data-expected yang memverifikasi warna, ketebalan teks, tebal garis kiri, dan jarak huruf — membuktikan bahwa keempat combinator menjangkau kelompok elemen yang berbeda pada struktur yang sama.