---
title: 'Gölge DOM'
source: 'https://academia.sh/tr/kurslar/tarayici-platformu/golge-dom'
course: 'Tarayıcı ve Web Platformu'
language: tr
updated: '2026-08-17T18:09:12+00:00'
license: 'CC BY-SA 4.0'
---

# Gölge DOM

Bir ögenin içine açılan ayrı belge ağacı; seçicinin durduğu sınır, biçemin iki yönlü yalıtımı, kalıtımın ve özel özelliklerin sınırdan geçişi, açık ile kapalı kip ve olay hedefinin çevrilmesi.

Önceki ders ögeye bir ad ve bir yaşam döngüsü verdi; içini açık bıraktı. Ölçüm rozetinin
işaretlemesi hâlâ belgenin ortak ağacındadır. Sayfanın herhangi bir yerinde yazılmış
`.deger { font-weight: 700 }` kuralı rozetin içindeki değeri de yakalar; rozetin kendi
kuralı sayfadaki başka bir `.deger` ögesine sızar; belgeye bağlanmış bir seçici rozetin iç
düğümlerini bulur ve onlara dokunur.

Yeniden kullanılabilir bir parçanın gereksinimi bunun tersidir. Bu ders, belge ağacının
içinde ayrı bir ağaç açan ve iki yönlü yalıtımı kuran mekanizmayı kurar.

## Gölge Kökü, Konak ve Işık Ağacı

Bir öge, kendisine bağlı ikinci bir ağaç edinebilir. Bu ağacın köküne **gölge kökü (shadow
root)**, ağacın kendisine **gölge ağacı (shadow tree)**, ağacı taşıyan ögeye **konak (host)**
denir.

Gölge ağacı belge ağacının bir parçası değildir; ayrı bir ağaçtır ve kendi kökü vardır.
Konak, iki ağacın birleştiği tek noktadır: belge ağacında bir öge, gölge ağacında bir kök
sahibi.

Konağın belgede yazılı kendi çocukları kaybolmaz; oldukları yerde dururlar. Bunlara
**ışık ağacı (light DOM)** denir. Gölge ağacı takılı bir ögede çizilen şey ışık ağacı değil
gölge ağacıdır; ışık ağacının içeriğinin nasıl geri kazanıldığı sonraki dersin konusudur.

Bir ögeye gölge ağacı takmak her etiket için mümkün değildir. Kendi iç yapısı olan ögeler
— form denetimleri, görsel, giriş alanı — buna kapalıdır; bunların zaten tarayıcı
tarafından yönetilen bir iç yapısı vardır.

## Seçicinin Durduğu Sınır

Yalıtımın ilk yüzü seçicidir. Belge ağacında yapılan bir sorgu gölge ağacına inmez; gölge
ağacında yapılan bir sorgu dışarı çıkmaz.

```js
// golge-sinir.mjs — secici sinirda durur, kalitim sinirdan gecer
const oge = (ad, ozn = {}, ...cocuklar) => {
  const d = { ad, ozn, cocuklar, ebeveyn: null, golge: null };
  for (const c of cocuklar) c.ebeveyn = d;
  return d;
};

// Golge kokunu konaga takar.
function golgeTak(konak, ...cocuklar) {
  const kok = { ad: "#golge-kok", ozn: {}, cocuklar, ebeveyn: null, konak, golge: null };
  for (const c of cocuklar) c.ebeveyn = kok;
  konak.golge = kok;
  return kok;
}

// Bir agacta dolasir; karsilastigi golge agaclarinin icine GIRMEZ.
function* agacta(kok) {
  yield kok;
  for (const c of kok.cocuklar) yield* agacta(c);
}

const sinifVar = (d, s) => (d.ozn.class ?? "").split(/\s+/).includes(s);
const yaz = (d) => `${d.ad}#${d.ozn.id ?? "-"}`;
const sorgu = (kok, sinif) => [...agacta(kok)].filter((d) => sinifVar(d, sinif)).map(yaz);

// Istasyon sayfasi: iki rozet; ilkinin golge agaci var, ikincisi duz isaretleme.
const rozetA = oge("olcum-rozeti", { class: "rozet", id: "sicaklik" });
golgeTak(rozetA,
  oge("div", { class: "kutu", id: "g-kutu" },
    oge("span", { class: "deger", id: "g-deger" }),
    oge("span", { class: "birim", id: "g-birim" })));

const rozetB = oge("p", { class: "rozet", id: "nem" },
  oge("span", { class: "deger", id: "l-deger" }));

const belge = oge("#belge", { id: "belge" }, oge("section", { id: "pano" }, rozetA, rozetB));

console.log("belge agacindan .rozet :", sorgu(belge, "rozet"));
console.log("belge agacindan .deger :", sorgu(belge, "deger"));
console.log("golge agacindan .deger :", sorgu(rozetA.golge, "deger"));
console.log("golge agacindan .rozet :", sorgu(rozetA.golge, "rozet"));

// Kalitilan ozellikler sinirdan gecer; secici tabanli kurallar gecmez.
const KALITILAN = new Set(["color", "font-size", "line-height"]);
const belgeKurali = { sinif: "deger", bildirim: { "font-weight": "700" } };
const konaktanGelen = { color: "#b23", "font-weight": "400" };

function hesapla(dugum) {
  const deger = Object.fromEntries(
    Object.entries(konaktanGelen).filter(([ad]) => KALITILAN.has(ad)));
  const belgeAgacinda = [...agacta(belge)].includes(dugum);
  if (belgeAgacinda && sinifVar(dugum, belgeKurali.sinif)) Object.assign(deger, belgeKurali.bildirim);
  return deger;
}

const golgeDeger = [...agacta(rozetA.golge)].find((d) => d.ozn.id === "g-deger");
const belgeDeger = [...agacta(belge)].find((d) => d.ozn.id === "l-deger");

console.log("hesaplanan span#l-deger:", hesapla(belgeDeger));
console.log("hesaplanan span#g-deger:", hesapla(golgeDeger));
```

```
belge agacindan .rozet : [ 'olcum-rozeti#sicaklik', 'p#nem' ]
belge agacindan .deger : [ 'span#l-deger' ]
golge agacindan .deger : [ 'span#g-deger' ]
golge agacindan .rozet : []
hesaplanan span#l-deger: { color: '#b23', 'font-weight': '700' }
hesaplanan span#g-deger: { color: '#b23' }
```

İlk dört satır sınırın simetrik olduğunu gösterir. Belgede `.deger` arayan sorgu iki
eşleşmeden yalnızca birini bulur; gölge ağacındaki `span#g-deger` görünmez. Ters yönde de
aynısı geçerlidir: gölge ağacında `.rozet` arayan sorgu, konağın kendisi o sınıfa sahip
olduğu hâlde boş döner — konak gölge ağacının dışındadır.

Bunun pratik iki sonucu vardır. Birincisi, gölge ağacındaki kimlikler belge kimlikleriyle
çakışmaz; her gölge ağacı kendi kimlik uzayına sahiptir. Aynı bileşeni sayfada on kez
kullanmak on tane aynı kimliği üretse bile çakışma doğmaz. İkincisi, bileşenin içine
dokunmak isteyen dış kod bunu ancak konaktan gölge köküne geçerek yapabilir — yani
kasıtlı ve görünür bir adımla.

## Biçemin İki Yönlü Yalıtımı

Yalıtımın ikinci yüzü biçemdir ve seçiciyle aynı kuraldan doğar. Basamaklama ve Özgüllük
dersinde tanımlanan eşleme, bir kuralın kendi ağacındaki ögelere uygulanmasıdır. Belgeye
yazılmış bir kuralın seçicisi gölge ağacındaki ögelere eşleşmez; gölge ağacına yazılmış bir
kural belge ağacına eşleşmez.

Çıktının son iki satırı bu ayrımı gösterir. Belge ağacındaki `span#l-deger` ögesine belge
kuralındaki `font-weight: 700` uygulanmış, gölge ağacındaki `span#g-deger` ögesine
uygulanmamıştır.

Sınırın biçem tarafında **iki tanımlı geçiş** vardır ve her ikisi de kasıtlıdır.

Birincisi **kalıtımdır**. Kalıtılan özellikler ağaç sınırını tanımaz: konağa uygulanan
yazı rengi, satır yüksekliği, yazı boyutu gölge ağacına devreder. Çıktıda her iki ögenin
de `color` değerini konaktan almış olması budur. Bu yüzden gölge ağacı biçemi tam bir
sıfırlama değildir; bileşen dışarıdan gelen tipografiye uyum sağlar ve bu genellikle
istenen davranıştır.

İkincisi **özel özelliklerdir**. Kalıtılan bir değer olarak tanımlandıkları için sınırdan
geçerler ve bileşene dışarıdan ayarlanabilir bir yüzey kazandırırlar. Bileşen, kendi
kurallarında bir özel özelliği yedekli değeriyle okur; sayfa o özelliği konakta
tanımlayarak bileşenin görünümünü, iç yapısına hiç dokunmadan değiştirir. Özel Özellikler
dersinde kurulan bu mekanizma, gölge ağacı ile birlikte bir bileşenin **biçem sözleşmesi**
hâline gelir.

Gölge ağacının içinden yazılan kurallar için iki seçici tanımlıdır. Biri konağın kendisini
hedefler ve bileşenin dış kutusunu biçemler; koşullu biçimi, konağın belgedeki bağlamına
ya da özniteliğine göre farklı biçem vermeyi sağlar. Diğeri, bileşenin dışarıya açtığı iç
parçaları hedefler: bileşen bir iç ögeyi ad vererek işaretler, dışarıdaki biçem o adı
kullanarak yalnızca işaretlenmiş parçalara erişir. Bu, kapsüllemeyi delmek değil,
kapsüllemenin içinde tanımlı bir pencere açmaktır — bileşen hangi parçalarının biçemlenmeye
açık olduğuna kendisi karar verir.

## Açık ve Kapalı Kip

Gölge ağacı takılırken iki kipten biri seçilir. **Açık kipte** konağın gölge kökü program
tarafından okunabilir; dışarıdaki kod bileşenin içine erişebilir. **Kapalı kipte** konak
üzerinden gölge köküne erişilemez; başvuru yalnızca bileşenin kendi kodunda tutulur.

Kapalı kip bir güvenlik sınırı değildir. Bileşenin kodu sayfayla aynı ortamda çalışır;
kararlı bir kod gölge köküne başka yollardan ulaşabilir. Kapalı kip bir **niyet
bildirimidir**: bileşenin iç yapısı arayüzünün parçası değildir, ona dayanan kod
kırılacaktır.

Bedeli de vardır. Kapalı bir ağaç, sayfanın erişilebilirlik denetimlerini, test
araçlarını ve hata ayıklamayı zorlaştırır. Yaygın seçim açık kiptir; kapsülleme sözleşmeyle
korunur, erişim engeliyle değil.

## Olayların Sınırı Aşması

Olay Modeli dersinde yayılım yolu kökten hedefe uzanan ata zinciri olarak tanımlanmıştı.
Gölge ağacı bu zincire bir ek getirir: yol, gölge kökünde durmaz, konağa atlar ve belgeye
kadar sürer. Buna **birleşik yol (composed path)** denir.

Yol dışarı taştığında bir sorun doğar. Belgeye bağlanmış bir dinleyici, olayın hedefi
olarak gölge ağacının içindeki bir düğümü görürse kapsülleme delinmiş olur. Bu yüzden
tarayıcı hedefi **çevirir (retargeting)**: her dinleyici, olayın hedefi olarak kendi
ağacındaki en yakın karşılığını görür.

```js
// hedef-cevirme.mjs — olay golge sinirini asarken hedef nasil degisir
const oge = (ad, ...cocuklar) => {
  const d = { ad, cocuklar, ebeveyn: null, konak: null, golge: null };
  for (const c of cocuklar) c.ebeveyn = d;
  return d;
};

function golgeTak(konak, ...cocuklar) {
  const kok = { ad: "#golge-kok", cocuklar, ebeveyn: null, konak, golge: null };
  for (const c of cocuklar) c.ebeveyn = kok;
  konak.golge = kok;
  return kok;
}

// Bir dugumun ait oldugu agacin koku: ya belge ya bir golge kok.
const agacKoku = (d) => { let a = d; while (a.ebeveyn) a = a.ebeveyn; return a; };

// Birlesik yol: hedeften baslar, agac koklerinde konaga atlayarak belgeye kadar cikar.
function birlesikYol(hedef) {
  const yol = [];
  for (let d = hedef; d; d = d.ebeveyn ?? d.konak) yol.push(d);
  return yol;
}

// Bir dinleyici icin hedef: birlesik yolda dinleyiciyle AYNI agacta olan ilk dugum.
function cevrilmisHedef(hedef, dinleyici) {
  const dinleyiciAgaci = agacKoku(dinleyici);
  return birlesikYol(hedef).find((d) => agacKoku(d) === dinleyiciAgaci);
}

const dugme = oge("button.kaydet");
const kutu = oge("div.kutu", dugme);
const rozet = oge("olcum-rozeti");
const golgeKok = golgeTak(rozet, kutu);
const pano = oge("section#pano", rozet);
const belge = oge("#belge", pano);

console.log("birlesik yol:", birlesikYol(dugme).map((d) => d.ad).join(" → "));
console.log();
console.log("dinleyicinin dugumu   hedef olarak gordugu");
for (const d of [dugme, kutu, golgeKok, rozet, pano, belge])
  console.log(d.ad.padEnd(22), cevrilmisHedef(dugme, d).ad);

// composed: false olan olay golge kokunden yukari cikmaz.
const yayilanlar = (hedef, birlesik) => {
  const yol = birlesikYol(hedef);
  if (birlesik) return yol;
  const sinir = yol.findIndex((d) => d.ad === "#golge-kok");
  return sinir === -1 ? yol : yol.slice(0, sinir + 1);
};

console.log();
console.log("composed: true  →", yayilanlar(dugme, true).map((d) => d.ad).join(" → "));
console.log("composed: false →", yayilanlar(dugme, false).map((d) => d.ad).join(" → "));
```

```
birlesik yol: button.kaydet → div.kutu → #golge-kok → olcum-rozeti → section#pano → #belge

dinleyicinin dugumu   hedef olarak gordugu
button.kaydet          button.kaydet
div.kutu               button.kaydet
#golge-kok             button.kaydet
olcum-rozeti           olcum-rozeti
section#pano           olcum-rozeti
#belge                 olcum-rozeti
```

```
composed: true  → button.kaydet → div.kutu → #golge-kok → olcum-rozeti → section#pano → #belge
composed: false → button.kaydet → div.kutu → #golge-kok
```

Gölge ağacının içindeki üç dinleyici gerçek hedefi, dışındaki üç dinleyici konağı görür.
Belgeye bağlanmış bir olay devri kodu, bileşenin içinde hangi düğmeye tıklandığını
öğrenemez; yalnızca "ölçüm rozetine tıklandı" bilgisini alır. Bileşenin dışarıya ne
bildireceğine kendisi karar verir ve bunu genellikle kendi tanımladığı bir olay türüyle
yapar.

Son iki satır ikinci ayrımı gösterir. Bir olayın gölge sınırını aşıp aşmayacağı olay
nesnesinin bir alanıyla belirlenir. Sınırı aşmayan bir olay gölge kökünde durur ve dışarıya
hiç ulaşmaz. Kullanıcı girdisinden doğan yerleşik olaylar sınırı aşar; bileşenin kendi
tanımladığı olaylar ise varsayılan olarak aşmaz ve dışarı çıkması isteniyorsa bu açıkça
bildirilir.

## Özet

- Gölge ağacı, konak ögesine bağlı ayrı bir belge ağacıdır; konağın belgedeki kendi
  çocukları ışık ağacı olarak yerinde kalır.
- Seçici sınırı iki yönde de aşmaz: belge sorgusu gölge ağacını, gölge sorgusu belge
  ağacını görmez. Kimlik uzayları da ayrıdır.
- Biçem eşlemesi seçiciyle aynı sınıra uyar; kalıtılan özellikler ve özel özellikler ise
  sınırdan geçer ve bileşenin biçem sözleşmesini oluşturur.
- Bileşen, dışarıdan biçemlenebilecek iç parçalarını ad vererek açar; kapsülleme bu
  pencerelerin dışında korunur.
- Kapalı kip erişimi zorlaştırır ama bir güvenlik sınırı değildir; taşıdığı bilgi, iç
  yapının arayüzün parçası olmadığıdır.
- Olay yolu gölge kökünden konağa atlayarak sürer; her dinleyici hedefi kendi ağacındaki
  karşılığıyla görür ve sınırı aşmayan olaylar gölge kökünde durur.

## Sonraki Adım

Bu ders gölge ağacının nasıl yalıtıldığını gösterdi, ama içeriğinin nereden geldiğini
göstermedi. İki soru açık kaldı. Birincisi, bileşenin iç yapısı her örnek için düğüm düğüm
kurulursa on beş rozet on beş kez aynı kurulum kodunu çalıştırır; işaretlemenin çizilmeden
duran ve ucuz çoğaltılabilen bir biçimi gerekir. İkincisi, konağın belgede yazılı ışık
ağacı şu an hiçbir yerde görünmüyor; bileşenin dışarıdan aldığı içeriği gölge ağacının
belirlediği bir yere yerleştirmesi gerekir. Sonraki ders bu iki mekanizmayı — çizilmeyen
işaretleme kabını ve içeriğin yerleştirildiği noktaları — birlikte kurar.
