---
title: 'Özel Özellikler'
source: 'https://academia.sh/tr/kurslar/duzen-ve-duyarli-tasarim/ozel-ozellikler'
course: 'Düzen Sistemleri ve Duyarlı Tasarım'
language: tr
updated: '2026-08-17T18:09:29+00:00'
license: 'CC BY-SA 4.0'
---

# Özel Özellikler

Özel özelliklerin bildirildiği ögede hesaplanması, kalıtımın hesaplanmış değeri taşıması, yedek değer zincirleri, hesaplanan değerde geçersizlik ve bileşenin biçem arayüzünün kurulması.

Önceki dersin bileşen dosyasındaki her kural bir ada başvuruyor: `var(--cizgi)`,
`var(--uyari)`, `var(--aralik-1)`. Bu adlar CSS ile Görsel Sunum kursunda kök ögede
tanımlandı ve o kurs için yeterliydi.

Bileşen mimarisi daha fazlasını ister. Bir kart varyantı yalnız zemin rengini değiştirmeli;
yan bilgi bölümü kendi renk ölçeğini taşımalı; bir bileşen, dışarıdan hangi değerlerin
ayarlanabileceğini bildirmeli. Bu ders özel özelliklere mimari bir araç olarak bakar ve
önce hesaplanma anını netleştirir.

## Hesaplanma Anı

**Özel özellik (custom property)** iki tire ile başlayan bir addır ve `var()` ile okunur.
Belirleyici kuralı, değerinin **bildirildiği ögede** hesaplanmasıdır.

Bu, kalıtımın ham metni değil **hesaplanmış değeri** taşıdığı anlamına gelir. Kök ögede
`--kart-zemin: var(--zemin)` yazıldığında, kökteki `--zemin` değeri yerine konur ve alt
ağaca giden şey artık o renktir. Bir alt ögede `--zemin` yeniden tanımlansa bile kökte
hesaplanmış `--kart-zemin` değişmez.

Aşağıdaki program bunu bir ağaç üzerinde çözüyor.

```js
// ozelozellik.mjs — ozel ozelliklerin hesaplanma ani, kalitim, yedek deger ve gecersizlik davranisi
// Kural: bir ozel ozelligin degeri, BILDIRILDIGI ogede hesaplanir; alt agaca hesaplanmis
// deger kalitilir. Alt agacta bir kaynak ozelligin yeniden tanimlanmasi, ustte hesaplanmis
// bir tureve geriye donuk etki etmez.
const AGAC = {
  ad: ":root",
  bildirim: { "--zemin": "hsl(203 18% 97%)", "--metin": "hsl(211 29% 16%)",
              "--kart-zemin": "var(--zemin)", "--aralik-1": "1.5rem" },
  cocuk: [{
    ad: ".yan-bilgi",
    bildirim: { "--zemin": "hsl(203 18% 92%)" },            // yalniz --zemin yeniden tanimli
    cocuk: [{
      ad: ".olcum-kart",
      bildirim: {},
      cocuk: [
        { ad: ".olcum-kart--uyari", bildirim: { "--kart-zemin": "hsl(0 66% 96%)" }, cocuk: [] },
        { ad: ".olcum-kart--sade",  bildirim: { "--kart-zemin": "yanlis-deger" },   cocuk: [] },
        { ad: ".olcum-kart--yerel", bildirim: { "--kart-zemin": "var(--zemin)" },   cocuk: [] },
      ],
    }],
  }],
};

const VAR_KALIBI = /var\(\s*(--[\w-]+)\s*(?:,\s*([^()]*(?:\([^()]*\)[^()]*)*))?\)/;

// metin icindeki var() basvurularini coz; ara(ad) bir ozel ozelligin degerini dondurur
function coz(metin, ara) {
  let s = metin, adim = 0;
  while (VAR_KALIBI.test(s)) {
    if (++adim > 50) return { deger: null, neden: "dongu" };
    const [tam, ad, yedek] = s.match(VAR_KALIBI);
    const bulunan = ara(ad);
    if (bulunan && bulunan.neden) return bulunan;                       // dongu yukari tasinir
    if (!bulunan || bulunan.deger === null) {
      if (yedek === undefined) return { deger: null, neden: `${ad} tanimsiz, yedek yok` };
      s = s.replace(tam, yedek);
    } else {
      s = s.replace(tam, bulunan.deger);
    }
  }
  return { deger: s.trim(), neden: null };
}

// bir ogenin ozel ozellik haritasi: kalitilan harita + kendi bildirimlerinin hesaplanmasi
function harita(dugum, kalitilan) {
  const sonuc = { ...kalitilan };
  const cozuluyor = new Set();
  const ara = (ad) => {
    if (ad in dugum.bildirim) {
      if (cozuluyor.has(ad)) return { deger: null, neden: "dongu" };
      cozuluyor.add(ad);
      const c = coz(dugum.bildirim[ad], ara);
      cozuluyor.delete(ad);
      return c;
    }
    return ad in kalitilan ? { deger: kalitilan[ad], neden: null } : null;
  };
  for (const ad of Object.keys(dugum.bildirim)) {
    const c = ara(ad);
    sonuc[ad] = c.deger;                                   // gecersizse null kalir
  }
  return sonuc;
}

const GECERLI_RENK = /^(hsl\(|rgb\(|#)/;
function gez(dugum, kalitilan = {}, yol = []) {
  const h = harita(dugum, kalitilan);
  const ad = [...yol, dugum.ad];
  const c = coz("var(--kart-zemin, var(--zemin))", (n) => (n in h ? { deger: h[n], neden: null } : null));
  let sonuc;
  if (c.deger === null) sonuc = `GECERSIZ (${c.neden})`;
  else if (!GECERLI_RENK.test(c.deger)) sonuc = `"${c.deger}" -> hesaplanan degerde gecersiz`;
  else sonuc = c.deger;
  console.log("  " + ad.join(" > ").padEnd(62) + sonuc);
  for (const c2 of dugum.cocuk) gez(c2, h, ad);
}

console.log("--- agacta background-color: var(--kart-zemin, var(--zemin)) ---");
gez(AGAC);

console.log("\n--- kok ogedeki yedek deger zincirleri ---");
const KOK = harita(AGAC, {});
const kokAra = (n) => (n in KOK ? { deger: KOK[n], neden: null } : null);
for (const yazim of [
  "var(--zemin)",
  "var(--yok)",
  "var(--yok, var(--zemin))",
  "var(--yok, var(--de-yok, hsl(0 0% 100%)))",
  "calc(var(--aralik-1) * 2)",
]) {
  const c = coz(yazim, kokAra);
  console.log(`  ${yazim.padEnd(42)} -> ${c.deger === null ? "GECERSIZ: " + c.neden : c.deger}`);
}

console.log("\n--- dongu ---");
const D = { ad: ":root", bildirim: { "--a": "var(--b)", "--b": "var(--a)" }, cocuk: [] };
console.log("  --a: var(--b); --b: var(--a);  -> --a degeri:", harita(D, {})["--a"]);
```

```
--- agacta background-color: var(--kart-zemin, var(--zemin)) ---
  :root                                                         hsl(203 18% 97%)
  :root > .yan-bilgi                                            hsl(203 18% 97%)
  :root > .yan-bilgi > .olcum-kart                              hsl(203 18% 97%)
  :root > .yan-bilgi > .olcum-kart > .olcum-kart--uyari         hsl(0 66% 96%)
  :root > .yan-bilgi > .olcum-kart > .olcum-kart--sade          "yanlis-deger" -> hesaplanan degerde gecersiz
  :root > .yan-bilgi > .olcum-kart > .olcum-kart--yerel         hsl(203 18% 92%)

--- kok ogedeki yedek deger zincirleri ---
  var(--zemin)                               -> hsl(203 18% 97%)
  var(--yok)                                 -> GECERSIZ: --yok tanimsiz, yedek yok
  var(--yok, var(--zemin))                   -> hsl(203 18% 97%)
  var(--yok, var(--de-yok, hsl(0 0% 100%)))  -> hsl(0 0% 100%)
  calc(var(--aralik-1) * 2)                  -> calc(1.5rem * 2)

--- dongu ---
  --a: var(--b); --b: var(--a);  -> --a degeri: null
```

İkinci satır dersin en sık atlanan noktasıdır. `.yan-bilgi` ögesi `--zemin` değerini
değiştiriyor, ama zemini `hsl(203 18% 97%)` kalıyor — çünkü okuduğu `--kart-zemin`, kök
ögede zaten hesaplanmıştır.

Son satır çözümü gösteriyor: `--kart-zemin` alt ağaçta yeniden bildirildiğinde, `var(--zemin)`
o ögede çözülür ve `hsl(203 18% 92%)` çıkar. Kural şudur: türev bir değerin bağlamdan
etkilenmesi isteniyorsa, türev o bağlamda bildirilmelidir.

`calc(var(--aralik-1) * 2)` satırı bir başka ayrıntıyı gösteriyor: yerine koyma yalnız
metin düzeyindedir. Değerin anlamlı olup olmadığı, yerine koyma bittikten sonra sınanır.

## Yedek Değer ve Geçersizlik

`var()` ikinci bir argüman alır: adın tanımsız olduğu durumda kullanılacak **yedek değer**.
Yedek değerler iç içe yazılabilir ve çıktının ikinci bloğu iki katlı bir zinciri çözüyor.

Yedeğin devreye girmediği bir durum vardır ve tuzak oradadır: ad **tanımlıysa** ama değeri
kullanıldığı yerde anlamsızsa, yedek çalışmaz. `--kart-zemin: yanlis-deger` bildirimi
tanımlıdır; `background-color` bu değeri alır ve o noktada geçersiz olur.

Bu duruma **hesaplanan değerde geçersizlik (invalid at computed-value time)** denir ve
sonucu, ayrıştırma sırasındaki geçersizlikten farklıdır:

- Ayrıştırma sırasında geçersiz bir bildirim **atılır**; aynı özelliğe yazan önceki bildirim
  yerinde kalır.
- Hesaplanan değerde geçersiz bir bildirim atılmaz; özelliği `unset` durumuna getirir. Yani
  kalıtılan özelliklerde kalıtılan değer, kalıtılmayanlarda başlangıç değeri geçerli olur.

Önceki kural yerinde kalmadığı için sonuç genellikle beklenmedik olur. Bir renk bildirimi
yanlış bir özel özellik yüzünden düştüğünde, ögenin rengi ana ögesinden gelir.

Döngü ayrı bir durumdur: birbirine başvuran iki özel özellik hiçbir değer üretmez ve ikisi
de tanımsız sayılır.

## Kayıtlı Özellikler

`@property` kuralı bir özel özelliği **kaydeder**: değerinin sözdizimini, kalıtılıp
kalıtılmayacağını ve başlangıç değerini bildirir.

```css
@property --kart-zemin {
  syntax: "<color>";
  inherits: true;
  initial-value: hsl(203 18% 97%);
}
```

Kaydın üç sonucu vardır. Birincisi tip denetimidir: bildirilen sözdizimine uymayan bir değer
kaydın başlangıç değerine düşer, hesaplanan değerde geçersizlik oluşmaz. İkincisi kalıtımın
denetlenebilmesidir; `inherits: false` yazılan bir özellik yalnız bildirildiği ögede geçerli
olur. Üçüncüsü hareketle ilgilidir: kayıtsız bir özel özellik yalnız metindir ve ara değeri
hesaplanamaz, kayıtlı bir renk ya da uzunluk ise geçişe ve anahtar karelere girebilir.

Üçüncü sonuç, önceki konudaki hareket bildirimleriyle birleşir: bir renk ölçeğinin kendisi
animasyona sokulabilir hâle gelir.

## Bileşenin Biçem Arayüzü

Buraya kadarki kurallar bir mimari kalıba varır. Bileşen, dışarıya açtığı ayar noktalarını
özel özellik olarak tanımlar; içeride yalnız bu adları okur.

```css
.olcum-kart {
  --kart-zemin: var(--zemin);
  --kart-cerceve: var(--cizgi);
  --kart-vurgu-yolu: -8px;

  background-color: var(--kart-zemin);
  border: 1px solid var(--kart-cerceve);
}

.olcum-kart:hover { transform: translateY(var(--kart-vurgu-yolu)); }

.olcum-kart--uyari { --kart-zemin: hsl(0 66% 96%); --kart-cerceve: var(--uyari); }
.olcum-kart--durgun { --kart-vurgu-yolu: 0px; }
```

Değiştiriciler artık bildirim ezmiyor, **değer veriyor**. `.olcum-kart--uyari` kuralı
`background-color` yazmıyor; yalnız bileşenin okuduğu adı değiştiriyor. Bunun üç sonucu var:
özgüllük yarışı çıkmaz, varyant sayısı arttıkça kural sayısı artmaz ve bileşenin neyin
ayarlanabilir olduğu dosyanın ilk satırlarından okunur.

Ad öneki de bir sözleşmedir: `--kart-` ile başlayanlar bileşenin arayüzüdür, `--zemin` gibi
öneksiz adlar sayfa ölçeğinden gelir. İkisi karışırsa bileşenin dışarıdan ne beklediği
belirsizleşir.

## Tema Yönetimi

Tema, aynı arayüzü farklı değerlerle doldurmaktır. İki katmanlı bir ölçek bunu ayırır:
ham değerleri tutan adlar ve işlevi adlandıran adlar. Tema yalnız ikinci katmanı değiştirir.

```css
:root {
  --gri-95: hsl(203 18% 97%);
  --gri-15: hsl(211 29% 16%);

  --zemin: var(--gri-95);
  --metin: var(--gri-15);
}

[data-tema="koyu"] {
  --zemin: var(--gri-15);
  --metin: var(--gri-95);
}
```

Tema bir öznitelikle bildirildiği için alt ağaç ölçeğinde de uygulanabilir: sayfanın tamamı
açık, tek bir bölüm koyu olabilir. Kalıtım bunu kendiliğinden sağlar; ek bir kural gerekmez.

Aynı yapı ortam sorgusuyla da sürülebilir — kullanıcının renk şeması tercihi, öznitelik
yerine sorgu içinde aynı iki bildirimi yazar. İki kaynak birlikte kullanılıyorsa hangisinin
öncelikli olduğu bir karardır: kullanıcının sayfa içinde yaptığı seçim genellikle sistem
tercihini ezer, çünkü daha sonra ve daha özgül yazılır.

## Özet

- Özel özellik bildirildiği ögede hesaplanır; alt ağaca hesaplanmış değer kalıtılır, ham
  metin değil.
- Bir türev değerin bağlamdan etkilenmesi için o bağlamda yeniden bildirilmesi gerekir;
  kaynak adı alt ağaçta değiştirmek üstte hesaplanmış türevi değiştirmez.
- Yedek değer yalnız ad **tanımsızsa** çalışır; tanımlı ama anlamsız bir değer hesaplanan
  değerde geçersizlik üretir ve özelliği `unset` durumuna getirir.
- `@property` kaydı sözdizimi, kalıtım ve başlangıç değeri bildirir; kayıtlı özellikler tip
  denetimi kazanır ve geçişe girebilir.
- Bileşen, ayar noktalarını önekli özel özellik olarak açtığında varyantlar bildirim ezmek
  yerine değer verir; özgüllük düz kalır ve arayüz okunur olur.

## Sonraki Adım

Buradaki bütün adlar tarayıcıda, çalışma zamanında çözülüyor. Bir başka araç sınıfı aynı
işlerin bir bölümünü daha belge tarayıcıya ulaşmadan yapar: iç içe yazımı düzleştirmek,
yinelenen blokları tek yerde tutmak, dosyaları birleştirmek. Sonraki ders derleme zamanında
çalışan biçem araçlarını ele alır ve hangi işin çalışma zamanına bırakılması gerektiğini
ayırır.
