Ders 06 / 19
Tasarım Belirteçleri
Belirteçlerin ilkel, anlamsal ve bileşen katmanlarına ayrılması, katmanlar arası başvuru kurallarının konması ve belirteç grafiğinin döngü, tanımsız başvuru, katman ihlali ile boşta kalan belirteç için çözümlenmesi.
İçindekiler
Sistemin kuruluş kararları tamamlandı: kapsam çizildi, ölçekler seçildi, tasarım dili denetlenebilir hâle geldi. Bu kararların hepsi şu ana kadar metin olarak duruyor. Bir arayüz metni okuyamaz; adlandırılmış değerler okur.
Tasarım belirteci (design token), bir tasarım kararının makine tarafından okunabilen adlandırılmış karşılığıdır. Tasarım Sistemi Nedir dersinde adlandırmanın değişiklik yeri sayısını 3.88 kat azalttığı hesaplanmıştı; bu ders o adların nasıl düzenleneceğini kurar. Sorun tek bir liste tutmak değildir — tek bir liste, bir süre sonra hangi adın hangi amaçla konduğu belirsizleşen bir sözlüğe döner. Belirteçler katmanlanır ve katmanlar arası başvurular kurala bağlanır.
Üç Katman, İki Kural
İlkel katman ham değerleri taşır: renk basamakları, ölçek adımları, boyut basamakları.
İlkel belirteç bir sayıdır ya da bir renktir; bir amaç taşımaz. notr-500 bir gri tonudur ve
nerede kullanılacağını söylemez.
Anlamsal katman bir işi adlandırır ve bir ilkel belirtece bağlar. kenarlik bir iştir;
hangi gri olduğu ikinci sorudur. Renk Sistemi dersinde bu ayrım renkte kurulmuştu; belirteç
mimarisi aynı ayrımı aralık, boyut ve yarıçap için de kurar.
Bileşen katmanı tek bir bileşenin ayar noktalarını açar ve bir anlamsal belirtece bağlar.
dugme-zemin bir ayar noktasıdır. Özel Özellikler dersinde bileşenin dışarıya açtığı adlara
biçem arayüzü deniyordu; bileşen belirteçleri o arayüzün sistem düzeyindeki karşılığıdır.
Katmanlar arasındaki başvurular iki kurala bağlıdır. İlkel katman hiçbir belirtece başvurmaz; yalnız değişmez değer taşır. Bileşen katmanı yalnız anlamsal katmana başvurur; ilkel katmana doğrudan başvurmak yasaktır. Anlamsal katman ilkel ya da başka bir anlamsal belirtece başvurabilir.
İkinci kuralın gerekçesi Renk Sistemi dersinde verilmişti: bir bileşen --notr-600 yazdığı
anda sistem delinir, çünkü o bileşen artık rol yeniden atamasından ve tema değişiminden
etkilenmez. Kural yazılı olduğunda ihlali denetlenebilir hâle gelir.
// belirtec.mjs — uc katmanli belirtec grafiginin cozumlenmesi ve denetimi // Katman kurallari: // ilkel -> yalniz degismez deger tasir, baska belirtece basvuramaz // anlamsal -> ilkel ya da anlamsal belirtece basvurur // bilesen -> yalniz anlamsal belirtece basvurur const IZIN = { ilkel: [], anlamsal: ["ilkel", "anlamsal"], bilesen: ["anlamsal"] }; const BELIRTECLER = { // --- ilkel katman --- "notr-000": { katman: "ilkel", deger: "#ffffff" }, "notr-500": { katman: "ilkel", deger: "#757e8a" }, "notr-600": { katman: "ilkel", deger: "#5e656e" }, "notr-900": { katman: "ilkel", deger: "#212327" }, "ana-100": { katman: "ilkel", deger: "#dee9f7" }, "ana-600": { katman: "ilkel", deger: "#275ea5" }, "ana-800": { katman: "ilkel", deger: "#15335b" }, "adim-1": { katman: "ilkel", deger: "4px" }, "adim-2": { katman: "ilkel", deger: "8px" }, "adim-3": { katman: "ilkel", deger: "12px" }, "adim-4": { katman: "ilkel", deger: "16px" }, "adim-6": { katman: "ilkel", deger: "24px" }, "basamak-0": { katman: "ilkel", deger: "16px" }, "basamak-1": { katman: "ilkel", deger: "20px" }, "yaricap-1": { katman: "ilkel", deger: "4px" }, // --- anlamsal katman --- yuzey: { katman: "anlamsal", deger: "{notr-000}" }, "metin-birincil": { katman: "anlamsal", deger: "{notr-900}" }, "metin-ikincil": { katman: "anlamsal", deger: "{notr-600}" }, kenarlik: { katman: "anlamsal", deger: "{notr-500}" }, "eylem-ana": { katman: "anlamsal", deger: "{ana-600}" }, "eylem-ana-uzeri": { katman: "anlamsal", deger: "{notr-000}" }, "vurgu-soluk": { katman: "anlamsal", deger: "{ana-100}" }, "vurgu-soluk-uzeri": { katman: "anlamsal", deger: "{ana-800}" }, "aralik-grup-ici": { katman: "anlamsal", deger: "{adim-2}" }, "aralik-blok-arasi": { katman: "anlamsal", deger: "{adim-4}" }, "aralik-bolum-arasi": { katman: "anlamsal", deger: "{adim-6}" }, "govde-boyutu": { katman: "anlamsal", deger: "{basamak-0}" }, "baslik-boyutu": { katman: "anlamsal", deger: "{basamak-1}" }, "yaricap-varsayilan": { katman: "anlamsal", deger: "{yaricap-1}" }, "uyari-zemini": { katman: "anlamsal", deger: "{uyari-kenarligi}" }, // dongu "uyari-kenarligi": { katman: "anlamsal", deger: "{uyari-zemini}" }, // dongu "aralik-sikisik": { katman: "anlamsal", deger: "{adim-1}" }, // hicbir yerden basvurulmuyor // --- bilesen katmani --- "dugme-zemin": { katman: "bilesen", deger: "{eylem-ana}" }, "dugme-metin": { katman: "bilesen", deger: "{eylem-ana-uzeri}" }, "dugme-ic-bosluk-y": { katman: "bilesen", deger: "{aralik-grup-ici}" }, "dugme-ic-bosluk-x": { katman: "bilesen", deger: "{aralik-blok-arasi}" }, "dugme-yaricap": { katman: "bilesen", deger: "{yaricap-varsayilan}" }, "kart-zemin": { katman: "bilesen", deger: "{yuzey}" }, "kart-kenarlik": { katman: "bilesen", deger: "{notr-500}" }, // katman ihlali: ilkele dogrudan "kart-ic-bosluk": { katman: "bilesen", deger: "{aralik-blok-arasi}" }, "kayit-baslik-boyutu": { katman: "bilesen", deger: "{baslik-boyutu}" }, "kayit-ustveri-rengi": { katman: "bilesen", deger: "{metin-ucuncul}" }, // tanimsiz basvuru "etiket-zemin": { katman: "bilesen", deger: "{vurgu-soluk}" }, "etiket-metin": { katman: "bilesen", deger: "{vurgu-soluk-uzeri}" }, }; const BASVURU = /^\{([\w-]+)\}$/; const hedef = (ad) => { const m = BELIRTECLER[ad].deger.match(BASVURU); return m ? m[1] : null; }; // --- cozumleme ---------------------------------------------------------------- function coz(ad) { const gorulen = new Set(); let su = ad; const zincir = [ad]; while (true) { if (!(su in BELIRTECLER)) return { deger: null, neden: `tanimsiz: ${su}`, zincir }; if (gorulen.has(su)) return { deger: null, neden: "dongu", zincir }; gorulen.add(su); const h = hedef(su); if (h === null) return { deger: BELIRTECLER[su].deger, neden: null, zincir }; su = h; zincir.push(su); } } // --- denetimler --------------------------------------------------------------- const kirik = []; const katmanIhlali = []; for (const ad of Object.keys(BELIRTECLER)) { const c = coz(ad); if (c.neden) kirik.push({ ad, ...c }); const h = hedef(ad); if (h === null) continue; const kendi = BELIRTECLER[ad].katman; const hedefKatman = h in BELIRTECLER ? BELIRTECLER[h].katman : null; if (hedefKatman && !IZIN[kendi].includes(hedefKatman)) { katmanIhlali.push({ ad, kendi, h, hedefKatman }); } } // Bilesen bicem dosyalarinda dogrudan okunan belirtecler. Her anlamsal belirtecin bir // bilesen belirteci karsiligi olmak zorunda degildir; bilesen katmani yalniz ayar noktasi // acilan yerlerde kurulur. const DOGRUDAN_KULLANIM = new Set([ "metin-birincil", "metin-ikincil", "kenarlik", "govde-boyutu", "aralik-bolum-arasi", "aralik-grup-ici", "yuzey", ]); // Basvurulma sayisi: bir belirtece kac belirtecten basvuruluyor? const gelen = Object.fromEntries(Object.keys(BELIRTECLER).map((a) => [a, 0])); for (const ad of Object.keys(BELIRTECLER)) { const h = hedef(ad); if (h && h in gelen) gelen[h]++; } // Bilesen katmani yaprak sayilir; ilkel ve anlamsal katmanda gelen basvurusu olmayan // belirtec bosta kalmistir. const bosta = Object.keys(BELIRTECLER).filter( (a) => BELIRTECLER[a].katman !== "bilesen" && gelen[a] === 0 && !DOGRUDAN_KULLANIM.has(a) ); const sayim = { ilkel: 0, anlamsal: 0, bilesen: 0 }; for (const a of Object.keys(BELIRTECLER)) sayim[BELIRTECLER[a].katman]++; console.log("katman belirtec sayisi"); for (const k of ["ilkel", "anlamsal", "bilesen"]) console.log(`${k.padEnd(10)} ${String(sayim[k]).padStart(15)}`); console.log(`toplam ${String(Object.keys(BELIRTECLER).length).padStart(15)}`); console.log("\nbilesen belirteci zincir deger"); for (const ad of Object.keys(BELIRTECLER).filter((a) => BELIRTECLER[a].katman === "bilesen")) { const c = coz(ad); console.log( `${ad.padEnd(24)} ${c.zincir.join(" > ").padEnd(51)} ${c.deger === null ? "COZULEMEDI (" + c.neden + ")" : c.deger}` ); } console.log("\ncozulemeyen belirtecler"); for (const k of kirik) console.log(` ${k.ad.padEnd(24)} ${k.neden.padEnd(24)} zincir: ${k.zincir.join(" > ")}`); console.log("\nkatman ihlalleri"); for (const i of katmanIhlali) { console.log(` ${i.ad} (${i.kendi}) -> ${i.h} (${i.hedefKatman}); izin verilen: ${IZIN[i.kendi].join(", ")}`); } console.log("\nbosta kalan belirtecler (ne belirtecten ne bicem dosyasindan basvuru var)"); for (const a of bosta) console.log(` ${a.padEnd(24)} katman: ${BELIRTECLER[a].katman}`); // --- zincir uzunlugu dagilimi -------------------------------------------------- const uzunluk = {}; for (const ad of Object.keys(BELIRTECLER)) { const c = coz(ad); if (c.neden) continue; uzunluk[c.zincir.length] = (uzunluk[c.zincir.length] || 0) + 1; } console.log("\nzincir uzunlugu belirtec sayisi"); for (const u of Object.keys(uzunluk).sort((a, b) => a - b)) { console.log(`${u.padStart(15)} ${String(uzunluk[u]).padStart(16)}`); } // --- katman gecisleri ---------------------------------------------------------- const gecis = {}; for (const ad of Object.keys(BELIRTECLER)) { const h = hedef(ad); if (!h || !(h in BELIRTECLER)) continue; const anahtar = `${BELIRTECLER[ad].katman} -> ${BELIRTECLER[h].katman}`; gecis[anahtar] = (gecis[anahtar] || 0) + 1; } console.log("\nkatman gecisi basvuru izinli mi"); for (const [g, n] of Object.entries(gecis).sort()) { const [kaynak, varis] = g.split(" -> "); console.log(`${g.padEnd(23)} ${String(n).padStart(7)} ${IZIN[kaynak].includes(varis) ? "evet" : "HAYIR"}`); }
katman belirtec sayisi
ilkel 15
anlamsal 17
bilesen 12
toplam 44
bilesen belirteci zincir deger
dugme-zemin dugme-zemin > eylem-ana > ana-600 #275ea5
dugme-metin dugme-metin > eylem-ana-uzeri > notr-000 #ffffff
dugme-ic-bosluk-y dugme-ic-bosluk-y > aralik-grup-ici > adim-2 8px
dugme-ic-bosluk-x dugme-ic-bosluk-x > aralik-blok-arasi > adim-4 16px
dugme-yaricap dugme-yaricap > yaricap-varsayilan > yaricap-1 4px
kart-zemin kart-zemin > yuzey > notr-000 #ffffff
kart-kenarlik kart-kenarlik > notr-500 #757e8a
kart-ic-bosluk kart-ic-bosluk > aralik-blok-arasi > adim-4 16px
kayit-baslik-boyutu kayit-baslik-boyutu > baslik-boyutu > basamak-1 20px
kayit-ustveri-rengi kayit-ustveri-rengi > metin-ucuncul COZULEMEDI (tanimsiz: metin-ucuncul)
etiket-zemin etiket-zemin > vurgu-soluk > ana-100 #dee9f7
etiket-metin etiket-metin > vurgu-soluk-uzeri > ana-800 #15335b
cozulemeyen belirtecler
uyari-zemini dongu zincir: uyari-zemini > uyari-kenarligi > uyari-zemini
uyari-kenarligi dongu zincir: uyari-kenarligi > uyari-zemini > uyari-kenarligi
kayit-ustveri-rengi tanimsiz: metin-ucuncul zincir: kayit-ustveri-rengi > metin-ucuncul
katman ihlalleri
kart-kenarlik (bilesen) -> notr-500 (ilkel); izin verilen: anlamsal
bosta kalan belirtecler (ne belirtecten ne bicem dosyasindan basvuru var)
adim-3 katman: ilkel
aralik-sikisik katman: anlamsal
zincir uzunlugu belirtec sayisi
1 15
2 16
3 10
katman gecisi basvuru izinli mi
anlamsal -> anlamsal 2 evet
anlamsal -> ilkel 15 evet
bilesen -> anlamsal 10 evet
bilesen -> ilkel 1 HAYIR
Grafik Dört Kusur Türü Üretir
Belirteç kümesi bir grafiktir: düğümler adlar, kenarlar başvurulardır. Grafik olarak görüldüğü anda üzerinde denetim yapılabilir hâle gelir ve dört ayrı kusur türü ortaya çıkar.
Döngü. uyari-zemini ile uyari-kenarligi birbirine başvuruyor. İkisi de hiçbir değer
üretmiyor. Özel Özellikler dersinde CSS düzeyinde aynı davranış gösterilmişti: birbirine
başvuran iki özel özellik tanımsız sayılır. Fark şudur ki oradaki sonuç çalışma zamanında
ortaya çıkar; buradaki denetim yayından önce çalışır.
Tanımsız başvuru. kayit-ustveri-rengi belirteci metin-ucuncul adına başvuruyor ve
böyle bir belirteç yok. Bu genellikle bir adın sonradan değiştirilmesinden ya da bir
belirtecin taslakta kalmasından doğar. Denetim çalışmadığında bileşen sessizce yanlış renge
düşer, çünkü tanımsız bir özel özellik hesaplanan değerde geçersizlik üretir ve renk ana
ögeden kalıtılır.
Katman ihlali. kart-kenarlik bileşen katmanında ama doğrudan notr-500 ilkel
belirtecine başvuruyor. Sonuç doğru bir renk üretiyor — çıktıda #757e8a görünüyor — ve bu
kusuru tehlikeli kılan da budur. Değer doğru olduğu için hiçbir görsel belirti vermez.
Etkisi ancak tema değiştiğinde ortaya çıkar: kart kenarlığı koyu temada açık temanın grisinde
kalır, çünkü rol katmanını atlamıştır.
Boşta kalan belirteç. adim-3 ve aralik-sikisik ne bir belirteçten ne bir biçem
dosyasından başvuru alıyor. Bunlar zararsız görünür ama sistemin okunmasını zorlaştırır: bir
liste ne kadar çok kullanılmayan ad taşırsa, kullananların hangisini seçeceği o kadar
belirsizleşir. Boşta kalan belirteç ya kaldırılır ya da neden durduğu yazılır.
Her Anlamsal Belirteç Bileşen Belirteci İstemez
Boşta kalan belirteç denetimi bir ayrım gerektiriyor ve bu ayrım mimari bir karardır.
metin-birincil, kenarlik, govde-boyutu gibi anlamsal belirteçlerin hiçbir bileşen
belirteci karşılığı yok. Bunlar biçem dosyalarında doğrudan okunuyor. Kod bunları
DOGRUDAN_KULLANIM kümesiyle biliyor ve boşta kalan sayılmıyorlar.
Ayrım şudur: bileşen katmanı her anlamsal belirteç için kurulmaz, yalnız bir ayar
noktası açılan yerlerde kurulur. dugme-zemin vardır, çünkü düğmenin varyantları zemini
değiştirir. kayit-baslik-boyutu vardır, çünkü kayıt kartının yoğun ve seyrek sürümleri
başlık boyutunu farklı seçer. Buna karşılık gövde metninin rengi hiçbir bileşende ayarlanmaz;
onun için bileşen belirteci açmak, hiçbir zaman kullanılmayacak bir ayar noktası üretir.
Katman geçişi tablosu bu dengeyi sayıyor: 10 bileşen belirteci anlamsal katmana başvuruyor, 15 anlamsal belirteç ilkel katmana. Bileşen katmanı anlamsal katmandan küçüktür ve olması gereken de budur. Bileşen katmanı anlamsal katmanla aynı boyuta ulaştıysa, ya her rol gereksiz yere sarmalanmıştır ya da anlamsal katman eksik kurulmuştur.
Zincir Uzunluğu Bir Ödünleşimdir
Zincir uzunluğu dağılımı üç değer gösteriyor: 15 belirteç doğrudan değer taşıyor, 16’sı bir adım sonra, 10’u iki adım sonra çözülüyor. Grafiğin derinliği üçle sınırlı.
Bu bir tesadüf değil, katman sayısının doğrudan sonucudur. Üç katmanlı bir sistemde en uzun zincir bileşen → anlamsal → ilkel olur. Anlamsal katmanın kendi içinde başvuru yapması bu sınırı esnetir — çıktıda iki anlamsal-anlamsal başvuru var — ve her esneme bir bedel taşır.
Bedel, izlenebilirliktir. Bir bileşenin neden o rengi aldığını anlamak için zincirin tamamı takip edilir. Üç adımlık bir zincir okunabilir; altı adımlık bir zincirde hangi adımın değiştirilmesi gerektiği belirsizleşir. Uzun zincir aynı zamanda bir işaret verir: aynı rol birden çok kez sarmalanmışsa, ara adımlardan biri gereksizdir.
Buna karşılık zinciri tümüyle düzleştirmek de yanlıştır. Bileşen belirteçlerinin doğrudan ilkel değerlere bağlandığı bir sistem, katman ihlalinin genelleştirilmiş hâlidir ve tema geçişini imkânsız kılar. Doğru hedef en kısa zincir değil, kural içinde en kısa zincirdir.
Yazılı Biçim ve Ad Sözleşmesi
Belirteçlerin biçemdeki karşılığı özel özelliklerdir. Katman ayrımı ad önekiyle görünür
kılınır; Özel Özellikler dersindeki --kart- öneki sözleşmesi burada üç katmana genişler.
:root { /* ilkel */ --notr-500: #757e8a; --ana-600: #275ea5; --adim-2: 8px; --adim-4: 16px; /* anlamsal */ --kenarlik: var(--notr-500); --eylem-ana: var(--ana-600); --aralik-grup-ici: var(--adim-2); --aralik-blok-arasi: var(--adim-4); } .dugme { /* bilesen: yalniz anlamsal adlara basvurur */ --dugme-zemin: var(--eylem-ana); --dugme-ic-bosluk-y: var(--aralik-grup-ici); --dugme-ic-bosluk-x: var(--aralik-blok-arasi); background-color: var(--dugme-zemin); padding: var(--dugme-ic-bosluk-y) var(--dugme-ic-bosluk-x); }
Bileşen belirteçlerinin kök ögede değil bileşenin kendi kuralında bildirilmesi bir kapsam
kararıdır. Bildirim bileşende durduğunda ad yalnız o alt ağaçta geçerli olur ve kök öge, her
bileşenin ayar noktalarını taşıyan bir listeye dönüşmez. Özel Özellikler dersindeki
hesaplanma anı kuralı burada da geçerlidir: --dugme-zemin düğme ögesinde hesaplanır,
dolayısıyla düğmenin bir üst ögesinde --eylem-ana yeniden tanımlanırsa düğme bunu devralır.
Ad sözleşmesinin son parçası ilkel katmanın adlandırmasıdır. İlkel adlar rol taşımaz, konum
taşır: notr-500, adim-2, basamak-1. Tipografik Ölçek dersinde basamak numarasının
anlam taşıyan addan daha dayanıklı olduğu gösterilmişti; aynı gerekçe bütün ilkel katman için
geçerlidir. Anlamı taşıyan tek katman anlamsal katmandır ve zaten adı bunu söyler.
Özet
- Tasarım belirteci, bir tasarım kararının makine tarafından okunabilen adlandırılmış karşılığıdır; belirteçler tek liste olarak değil katmanlı bir grafik olarak düzenlenir.
- Üç katman vardır: ilkel ham değeri, anlamsal işi, bileşen katmanı ayar noktasını taşır. İlkel katman başvuru yapmaz; bileşen katmanı yalnız anlamsal katmana başvurabilir.
- Grafik dört kusur türü üretir: döngü, tanımsız başvuru, katman ihlali ve boşta kalan belirteç. Katman ihlali en tehlikelisidir, çünkü doğru değer üretir ve ancak tema değiştiğinde görünür.
- Bileşen katmanı her anlamsal belirteç için kurulmaz, yalnız ayar noktası açılan yerlerde kurulur; bileşen katmanının anlamsal katmandan küçük kalması beklenir.
- Zincir uzunluğu katman sayısının sonucudur; uzun zincir izlenebilirliği düşürür, tümüyle düzleştirmek tema geçişini imkânsız kılar. Hedef kural içinde en kısa zincirdir.
- İlkel adlar konum taşır, anlamı yalnız anlamsal katman taşır; bileşen belirteçleri kök ögede değil bileşenin kendi kuralında bildirilir.
Sonraki Adım
Katman mimarisi kurulduğunda sıra katmanların içini doldurmaya gelir ve renk bu işin en çok kısıt taşıyan alanıdır. Bir renk belirteci yalnız bir ad ve bir değer değildir: hangi zemin üzerinde kullanılabileceği, hangi eşiği geçmesi gerektiği ve hangi durumda hangi türevine geçileceği de tanımın parçasıdır. Sonraki ders renk rollerini bir sözleşme olarak yazar, hangi ön planın hangi zemine düşebileceğini bildirir ve bu bildirimi kontrast oranıyla otomatik denetler.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.