---
title: 'Birleştirici Seçiciler'
source: 'https://academia.sh/tr/kurslar/css-temelleri/birlestirici-seciciler'
course: 'CSS ile Görsel Sunum'
language: tr
updated: '2026-08-17T18:09:17+00:00'
license: 'CC BY-SA 4.0'
---

# Birleştirici Seçiciler

Alt öge, çocuk, bitişik kardeş ve genel kardeş birleştiricileri; bir seçicinin sağdan sola değerlendirilmesi ve anahtar seçici kavramı.

Önceki dersin son kuralında `.kunye .ozet` yazılmıştı ve iki seçici arasındaki boşluğun bir
işleç olduğu söylenip geçilmişti. O boşluk **birleştirici (combinator)** adını taşır ve
seçiciye ağaçtaki konum sorusunu ekler: ögenin kendisi değil, nerede durduğu sorulur.

Bu ders dört birleştiriciyi tanımlar ve bir seçicinin nasıl değerlendirildiğini
gösterir. Değerlendirme sırası, hem sonucu hem de bir seçicinin maliyetini anlamak için
gereklidir.

## Dört Birleştirici

| Yazım | Ad | Sorduğu soru |
|---|---|---|
| `A B` | alt öge birleştiricisi (descendant) | B'nin atalarından biri A mı? |
| `A > B` | çocuk birleştiricisi (child) | B'nin doğrudan üstü A mı? |
| `A + B` | bitişik kardeş (adjacent sibling) | B'nin bir önceki kardeşi A mı? |
| `A ~ B` | genel kardeş (general sibling) | B'nin önceki kardeşlerinden biri A mı? |

Dördü de aynı biçimde okunur: **sağdaki seçilir, soldaki koşuldur.** `.olcum-cizelgesi td`
kuralı `td` ögelerini seçer; `.olcum-cizelgesi` yalnızca hangi `td` ögelerinin seçileceğini
daraltır. Sol taraf hiçbir zaman biçimlendirilmez.

Kardeş birleştiricileri yalnızca **geriye** bakar. `A + B` yazımı "A'dan sonra gelen B"
anlamındadır; "B'den sonra gelen A" diye bir birleştirici yoktur.

## Değerlendirme Sağdan Sola Yapılır

Bir seçici soldan sağa okunur ama sağdan sola değerlendirilir. Sebep, iki yönün maliyet
farkındadır.

Soldan sağa gidilseydi `.olcum-cizelgesi td` için önce bütün belgede o sınıfı taşıyan
ögeler bulunur, sonra her birinin **bütün alt ağacı** taranırdı. Sağdan sola gidildiğinde
ise her `td` ögesi için yalnızca atalar zinciri yukarı doğru izlenir; zincirin uzunluğu
ağacın derinliği kadardır. İkinci yol, bir ögenin biçemi hesaplanırken sorulan sorunun da
doğal yönüdür: "bu ögeye hangi kurallar uyuyor?"

Sağdaki bileşik seçiciye **anahtar seçici (key selector)** denir. Bir kuralın hangi ögeler
için sınanacağını belirleyen odur.

Aşağıdaki program dört birleştiriciyi sağdan sola değerlendirir. Ağaç, ölçüm çizelgesinin
gerçek yapısını taşır: satırlar `thead` ve `tbody` içinde gruplanmıştır.

```js
// birlestirici.mjs — dort birlestiriciyi sagdan sola degerlendirir
const agac = { ad: "body", sinif: [], cocuk: [
  { ad: "main", sinif: [], cocuk: [
    { ad: "table", sinif: ["olcum-cizelgesi"], cocuk: [
      { ad: "thead", sinif: [], cocuk: [
        { ad: "tr", sinif: [], cocuk: [{ ad: "th", sinif: [], cocuk: [] }] },
      ]},
      { ad: "tbody", sinif: [], cocuk: [
        { ad: "tr", sinif: [], cocuk: [
          { ad: "td", sinif: ["ad"], cocuk: [] },
          { ad: "td", sinif: ["deger"], cocuk: [] },
          { ad: "td", sinif: ["deger", "eksik"], cocuk: [] },
        ]},
      ]},
    ]},
    { ad: "p", sinif: ["not"], cocuk: [] },
    { ad: "table", sinif: [], cocuk: [
      { ad: "tbody", sinif: [], cocuk: [
        { ad: "tr", sinif: [], cocuk: [{ ad: "td", sinif: ["deger"], cocuk: [] }] },
      ]},
    ]},
  ]},
]};

// her dugume ust ve kardes bilgisi ekle
function bagla(d, ust = null) {
  d.ust = ust;
  d.cocuk.forEach((c, i) => { c.oncekiKardes = i > 0 ? d.cocuk[i - 1] : null; bagla(c, d); });
  return d;
}
bagla(agac);

const yol = (d) => (d.ust ? yol(d.ust) + " " : "") + d.ad + d.sinif.map((s) => "." + s).join("");
function* hepsi(d) { yield d; for (const c of d.cocuk) yield* hepsi(c); }

const basitEsler = (s, d) =>
  s === "*" ? true : s.startsWith(".") ? d.sinif.includes(s.slice(1)) : d.ad === s;

// bilesik secici: bosluksuz basit seciciler
function bilesikEsler(bilesik, d) {
  const parcalar = bilesik.match(/(^[a-z]+|\.[a-z-]+|\*)/g) ?? [];
  return parcalar.every((p) => basitEsler(p, d));
}

// secici: bilesik (birlestirici bilesik)*  — sagdan sola cozulur
function secERler(secici, dugum) {
  const jetonlar = secici.trim().split(/\s+/);
  let d = dugum;
  let i = jetonlar.length - 1;
  if (!bilesikEsler(jetonlar[i], d)) return false;
  i--;
  while (i >= 0) {
    const birlestirici = ">+~".includes(jetonlar[i]) ? jetonlar[i--] : " ";
    const hedef = jetonlar[i--];
    if (birlestirici === ">") { d = d.ust; if (!d || !bilesikEsler(hedef, d)) return false; }
    else if (birlestirici === "+") { d = d.oncekiKardes; if (!d || !bilesikEsler(hedef, d)) return false; }
    else if (birlestirici === "~") {
      let k = d.oncekiKardes;
      while (k && !bilesikEsler(hedef, k)) k = k.oncekiKardes;
      if (!k) return false; d = k;
    } else {
      let a = d.ust;
      while (a && !bilesikEsler(hedef, a)) a = a.ust;
      if (!a) return false; d = a;
    }
  }
  return true;
}

const denemeler = [
  "table td",
  ".olcum-cizelgesi td",
  ".olcum-cizelgesi > td",
  "tbody > tr > td",
  "td.ad + td",
  "td.ad ~ td",
  ".olcum-cizelgesi + p",
];
for (const s of denemeler) {
  const bulunan = [...hepsi(agac)].filter((d) => secERler(s, d));
  console.log(`${s.padEnd(26)} -> ${bulunan.length}`);
  for (const b of bulunan) console.log(`  ${yol(b)}`);
}
```

```
table td                   -> 4
  body main table.olcum-cizelgesi tbody tr td.ad
  body main table.olcum-cizelgesi tbody tr td.deger
  body main table.olcum-cizelgesi tbody tr td.deger.eksik
  body main table tbody tr td.deger
.olcum-cizelgesi td        -> 3
  body main table.olcum-cizelgesi tbody tr td.ad
  body main table.olcum-cizelgesi tbody tr td.deger
  body main table.olcum-cizelgesi tbody tr td.deger.eksik
.olcum-cizelgesi > td      -> 0
tbody > tr > td            -> 4
  body main table.olcum-cizelgesi tbody tr td.ad
  body main table.olcum-cizelgesi tbody tr td.deger
  body main table.olcum-cizelgesi tbody tr td.deger.eksik
  body main table tbody tr td.deger
td.ad + td                 -> 1
  body main table.olcum-cizelgesi tbody tr td.deger
td.ad ~ td                 -> 2
  body main table.olcum-cizelgesi tbody tr td.deger
  body main table.olcum-cizelgesi tbody tr td.deger.eksik
.olcum-cizelgesi + p       -> 1
  body main p.not
```

Bu gerçekleştirim, alt öge ve genel kardeş adımlarında geriye dönüş yapmaz: eşleşen ilk
atayı ya da ilk kardeşi seçer ve orada kalır. Gerçek bir eşleyici, sonraki adım
başarısızsa geri döner ve başka bir ata dener. Yukarıdaki yedi örnekte iki davranış aynı
sonucu verir.

## Sıfır Öge Döndüren Seçici

Üçüncü satır dikkat ister: `.olcum-cizelgesi > td` hiçbir öge döndürmedi, oysa
`.olcum-cizelgesi td` üç öge döndürdü. Aradaki tek fark bir işarettir.

Sebep ağaçtadır. Hücreler tablonun doğrudan çocuğu değildir; aradaki zincir
`table > tbody > tr > td` biçimindedir. Çocuk birleştiricisi tam bir adım ister ve o adım
`tbody` ögesine denk gelir.

Web'in Temelleri ve HTML kursunda ayrıştırıcının kaynakta yazılmamış ögeleri kurduğu
anlatılmıştı; `tbody` bunların en sık karşılaşılanıdır. Kaynak metinde `tbody` etiketi
yazılmamış olsa bile öge belgede vardır ve seçici o ögeyi görür. Bu, "etiket" ile "öge"
ayrımının biçem tarafındaki ilk somut sonucudur: **seçici kaynak metne değil, ayrıştırma
sonrası ağaca bakar.**

## Çocuk Birleştiricisi Ne Zaman Gerekir

Alt öge birleştiricisi derinlik gözetmez ve bu çoğu zaman istenen davranıştır. Ancak iç
içe geçmiş aynı türden yapılarda istenmeyen sonuç verir.

İstasyon sayfasının gezinme bölümü iç içe listeler taşıyorsa, `.gezinme li` seçicisi hem
üst düzey maddeleri hem alt maddeleri döndürür. Yalnızca üst düzeyi hedeflemek için
`.gezinme > ul > li` yazılır. Kural şudur: derinlik anlam taşıyorsa çocuk birleştiricisi,
taşımıyorsa alt öge birleştiricisi kullanılır.

## Kardeş Birleştiricileri Sıraya Bağlıdır

`td.ad + td` bir hücre döndürdü: ad hücresinden hemen sonraki değer hücresi. `td.ad ~ td`
ise ikisini birden döndürdü, çünkü genel kardeş birleştiricisi araya kaç kardeş girdiğine
bakmaz.

Kardeş birleştiricilerinin tipik kullanımı, iki ögenin **arasındaki** ilişkiyi
biçimlendirmektir. Ard arda gelen iki paragraf arasına boşluk koymak için:

```css
p + p { margin-block-start: 0.75em; }
```

Bu yazım, bir bölümün **ilk** paragrafına boşluk eklemez — çünkü onun önünde bir paragraf
kardeş yoktur. Aynı sonucu her paragrafa boşluk verip ilkini geri almakla da elde etmek
mümkündür; kardeş birleştiricisi ile yazılan biçim, kuralı tek bir yerde ve istisnasız
tutar.

## İstasyon Sayfasının Kuralları

Biçem dosyası bu dersle birlikte ağaçtaki konumları kullanmaya başlar:

```css
/* istasyon.css — 3. adım: ilişkiye bağlı kurallar */
.olcum-cizelgesi tbody td   { padding: 8px 12px; }
.olcum-cizelgesi tbody > tr { border-block-end: 1px solid #d5dbe0; }
.gezinme > ul > li          { display: inline-block; }
.olcum-cizelgesi + p        { font-size: 0.875rem; }
```

Son kural, çizelgeden hemen sonra gelen açıklama paragrafını küçültür. Paragrafa ayrı bir
sınıf vermek de aynı sonucu verirdi; aradaki fark, kuralın belgeye bir sınıf ekleme
gerektirip gerektirmemesidir. Belgeye dokunmadan çözülebilen bir biçem sorunu, biçem
dosyasında çözülür.

## Özet

- Birleştirici, seçiciye ağaçtaki konum sorusunu ekler; dördü de aynı biçimde okunur —
  sağdaki seçilir, soldaki koşuldur.
- Alt öge birleştiricisi derinlik gözetmez, çocuk birleştiricisi tam bir adım ister;
  bitişik kardeş bir önceki kardeşe, genel kardeş önceki kardeşlerin herhangi birine bakar.
- Seçici sağdan sola değerlendirilir; en sağdaki bileşik seçici anahtar seçicidir ve
  kuralın hangi ögeler için sınanacağını belirler.
- Seçici, kaynak metne değil ayrıştırma sonrası ağaca bakar; kaynakta yazılmayan `tbody`
  gibi ögeler zincire dâhildir ve çocuk birleştiricisini etkiler.
- Kardeş birleştiricileri yalnızca geriye bakar; "sonraki kardeşin öncesi" diye bir
  birleştirici yoktur.

## Sonraki Adım

Seçiciler şimdiye kadar öge adına, sınıfa, kimliğe ve ağaçtaki konuma baktı. Belgede bir
bilgi daha var ve henüz kullanılmadı: öznitelik değerleri. Form alanlarının türü, bir
bağlantının hedef adresi, veri öznitelikleriyle iliştirilen ölçüm birimleri — hepsi
özniteliklerde durur. Sonraki ders öznitelik seçicilerini ve değer eşleme biçimlerini
tanımlar.
