Ders 07 / 19
Renk Belirteçleri
Renk rollerinin bir sözleşme olarak yazılması, yasal ön plan–zemin çiftlerinin bildirilmesi, durum türevlerinin ayrım eşiğiyle sınanması ve sözleşmenin her temada otomatik denetlenmesi.
İçindekiler
Önceki ders belirteçlerin katmanlarını ve katmanlar arası başvuru kurallarını kurdu. O
mimaride bir renk belirteci bir addan ve bir başvurudan ibaretti: kenarlik adı notr-500
basamağına bağlanıyordu. Bu, bir rengin taşıdığı bilginin yalnız bir bölümüdür.
Bir renk belirtecinin geri kalanı nerede kullanılabileceğidir. metin-ikincil rolü hangi
zeminlerin üzerine düşebilir, hangi eşiği geçmek zorundadır, hangi durumda hangi türevine
geçilir. Bu bilgi yazılmadığında her bileşen kendi denetimini yapar ya da hiç yapmaz. Bu
ders renk belirteçlerini eşleşmeleriyle birlikte tanımlar ve tanımı denetlenebilir bir
sözleşmeye çevirir.
Sözleşme, Rol Listesinden Fazlasıdır
Renk Sistemi dersinde roller basamaklara bağlanmış ve eşleşmeler elle listelenip denetlenmişti. Sistem düzeyinde iki şey değişir.
Birincisi, eşleşme listesi bir sözleşme (contract) hâline gelir: bir bileşen yalnız sözleşmede yazılı bir çifti kullanabilir. Sözleşmede olmayan bir ön plan–zemin birleşimi bir tercih değil, bir ihlaldir. İkincisi, sözleşme her tema için yeniden çalıştırılır; tek bir temada geçmek yeterli değildir.
Rol kümesi de büyür. Renk Sistemi dersindeki on rolün üzerine üç küme daha eklenir: durum türevleri (üzerine gelme, basılı, devre dışı), işlevsel renk çiftleri ve odak halkası. Etkileşim Durumları dersinde durumların ölçülebilir biçimde ayrılması gerektiği ve bu kursta benimsenen ayrım eşiğinin 1.2 kontrast oranı olduğu belirlenmişti; sözleşme bu eşiği de denetler.
Sözleşmenin üçüncü parçası ölçütsüz eşleşmelerdir. Devre dışı bir denetimin metni,
erişilebilirlik ölçütlerinin kontrast koşulundan muaftır. Bu muafiyet sözleşmede eşiğin
yokluğu olarak değil, eşiğin açıkça null yazılması olarak görünür: karar verilmiş ve kayda
geçirilmiştir.
// renk.mjs — renk belirteclerinin sozlesme olarak yazilmasi ve sozlesmenin denetlenmesi function hslRgb(h, s, l) { s /= 100; l /= 100; const k = (n) => (n + h / 30) % 12; const a = s * Math.min(l, 1 - l); const f = (n) => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1))); return [f(0), f(8), f(4)].map((v) => Math.round(v * 255)); } const onaltilik = (rgb) => "#" + rgb.map((v) => v.toString(16).padStart(2, "0")).join(""); function kanal(v) { const s = v / 255; return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); } const parlaklik = ([r, g, b]) => 0.2126 * kanal(r) + 0.7152 * kanal(g) + 0.0722 * kanal(b); function kontrast(a, b) { const [x, y] = [parlaklik(a), parlaklik(b)].sort((p, q) => q - p); return (x + 0.05) / (y + 0.05); } // Ilkel katman: aileler ve basamak acikliklari (Renk Sistemi dersindeki rampa). const ACIKLIK = { "000": 100, "050": 97, 100: 92, 200: 84, 300: 74, 400: 62, 500: 50, 600: 40, 700: 31, 800: 22, 900: 14 }; const AILE = { notr: [214, 8], ana: [214, 62], basari: [145, 55], uyari: [38, 85], hata: [8, 68] }; const ilkel = (aile, basamak) => hslRgb(AILE[aile][0], AILE[aile][1], ACIKLIK[basamak]); // Anlamsal katman: her rol bir isi adlandirir ve bir ilkel basamaga baglanir. const ROL = { yuzey: ["notr", "000"], "yuzey-ikincil": ["notr", "050"], "yuzey-secili": ["ana", "100"], kenarlik: ["notr", "500"], "metin-birincil": ["notr", "900"], "metin-ikincil": ["notr", "600"], "metin-ucuncul": ["notr", "500"], "eylem-ana": ["ana", "600"], "eylem-ana-uzeri": ["notr", "000"], "eylem-ana-uzerine": ["ana", "700"], "eylem-ana-basili": ["ana", "800"], "eylem-devre-disi": ["notr", "200"], "eylem-devre-disi-uzeri": ["notr", "500"], "odak-halkasi": ["ana", "600"], "basari-zemin": ["basari", "100"], "basari-metin": ["basari", "800"], "uyari-zemin": ["uyari", "100"], "uyari-metin": ["uyari", "800"], "hata-zemin": ["hata", "100"], "hata-metin": ["hata", "700"], }; const renk = (rol) => ilkel(...ROL[rol]); console.log("rol aile basamak onaltilik"); for (const [ad, [aile, b]] of Object.entries(ROL)) { console.log(`${ad.padEnd(24)} ${aile.padEnd(7)} ${b.padStart(7)} ${onaltilik(renk(ad))}`); } // Sozlesme: hangi on plan hangi zemine dusebilir ve hangi esik gecerlidir. // esik null ise olcut uygulanmaz; bunun gerekcesi sozlesmede yazili olmak zorundadir. const SOZLESME = [ ["metin-birincil", "yuzey", 4.5], ["metin-birincil", "yuzey-ikincil", 4.5], ["metin-ikincil", "yuzey", 4.5], ["metin-ucuncul", "yuzey", 4.5], ["metin-birincil", "yuzey-secili", 4.5], ["kenarlik", "yuzey", 3.0], ["eylem-ana", "yuzey", 3.0], ["eylem-ana-uzeri", "eylem-ana", 4.5], ["eylem-ana-uzeri", "eylem-ana-uzerine", 4.5], ["eylem-ana-uzeri", "eylem-ana-basili", 4.5], ["eylem-devre-disi-uzeri", "eylem-devre-disi", null], ["odak-halkasi", "yuzey", 3.0], ["basari-metin", "basari-zemin", 4.5], ["uyari-metin", "uyari-zemin", 4.5], ["hata-metin", "hata-zemin", 4.5], ]; console.log("\non plan zemin kontrast esik sonuc"); let kalan = 0; for (const [on, zemin, esik] of SOZLESME) { const k = kontrast(renk(on), renk(zemin)); const sonuc = esik === null ? "olcut yok" : k >= esik ? "gecti" : "KALDI"; if (esik !== null && k < esik) kalan++; console.log( `${on.padEnd(24)} ${zemin.padEnd(22)} ${k.toFixed(2).padStart(7)}:1 ${(esik === null ? "-" : esik.toFixed(1)).padStart(6)} ${sonuc}` ); } console.log(`esigi gecemeyen eslesme: ${kalan} / ${SOZLESME.filter((s) => s[2] !== null).length}`); // Durum turevleri: her durum rolu taban rolden ayirt edilebilmelidir. // Olcut, Etkilesim Durumlari dersinde benimsenen 1.2 kontrast oranidir. const DURUM_ESIGI = 1.2; const DURUMLAR = [ ["eylem-ana-uzerine", "eylem-ana"], ["eylem-ana-basili", "eylem-ana-uzerine"], ["eylem-devre-disi", "yuzey"], ["yuzey-secili", "yuzey"], ["yuzey-ikincil", "yuzey"], ]; console.log("\ndurum rolu taban rol kontrast esik sonuc"); for (const [durum, taban] of DURUMLAR) { const k = kontrast(renk(durum), renk(taban)); console.log( `${durum.padEnd(24)} ${taban.padEnd(22)} ${k.toFixed(3).padStart(8)} ${DURUM_ESIGI.toFixed(1).padStart(5)} ${k >= DURUM_ESIGI ? "gecti" : "KALDI"}` ); } // Metin-ucuncul rolu icin: hangi notr basamak 4.5 esigini ilk saglar? console.log("\nnotr basamak yuzeye karsi 4.5 esigi 3.0 esigi (buyuk metin)"); for (const b of ["300", "400", "500", "600", "700"]) { const k = kontrast(ilkel("notr", b), renk("yuzey")); console.log( `${b.padStart(12)} ${k.toFixed(2).padStart(13)} ${(k >= 4.5 ? "gecti" : "KALDI").padStart(10)} ${(k >= 3.0 ? "gecti" : "KALDI").padStart(23)}` ); } // Ikincil yuzey icin: hangi notr basamak 1.2 ayrim esigini ilk saglar? console.log("\nnotr basamak yuzeye karsi 1.2 ayrim esigi uzerindeki metin-ikincil"); for (const b of ["050", "100", "200", "300"]) { const z = ilkel("notr", b); const ay = kontrast(z, renk("yuzey")); const mt = kontrast(renk("metin-ikincil"), z); console.log( `${b.padStart(12)} ${ay.toFixed(3).padStart(13)} ${(ay >= 1.2 ? "gecti" : "KALDI").padStart(16)} ` + `${(mt.toFixed(2) + ":1 " + (mt >= 4.5 ? "gecti" : "KALDI")).padStart(24)}` ); } // Koyu tema karsiligi: Koyu Tema dersinde korunum hesabiyla turetilmis degerler. const KOYU = { yuzey: "#212327", "yuzey-ikincil": "#34383d", "metin-birincil": "#ffffff", "metin-ikincil": "#989fa8", kenarlik: "#7b848f", "eylem-ana": "#89a9d2", "eylem-ana-uzeri": "#212327", "hata-metin": "#dd9589", }; const eksik = Object.keys(ROL).filter((r) => !(r in KOYU)); console.log(`\nkoyu tema karsiligi tanimli rol: ${Object.keys(KOYU).length} / ${Object.keys(ROL).length}`); console.log("koyu karsiligi eksik roller:"); for (const r of eksik) console.log(` ${r}`); // Sozlesmenin koyu temada denetlenebilen bolumu const cz = (h) => [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16)); console.log("\nkoyu temada denetlenebilen eslesmeler"); let denetlenen = 0; for (const [on, zemin, esik] of SOZLESME) { if (esik === null || !(on in KOYU) || !(zemin in KOYU)) continue; denetlenen++; const k = kontrast(cz(KOYU[on]), cz(KOYU[zemin])); console.log( ` ${on.padEnd(24)} ${zemin.padEnd(20)} ${k.toFixed(2).padStart(6)}:1 ${esik.toFixed(1).padStart(5)} ${k >= esik ? "gecti" : "KALDI"}` ); } console.log(`denetlenen: ${denetlenen} / ${SOZLESME.filter((s) => s[2] !== null).length}`);
rol aile basamak onaltilik
yuzey notr 000 #ffffff
yuzey-ikincil notr 050 #f7f7f8
yuzey-secili ana 100 #dee9f7
kenarlik notr 500 #757e8a
metin-birincil notr 900 #212327
metin-ikincil notr 600 #5e656e
metin-ucuncul notr 500 #757e8a
eylem-ana ana 600 #275ea5
eylem-ana-uzeri notr 000 #ffffff
eylem-ana-uzerine ana 700 #1e4980
eylem-ana-basili ana 800 #15335b
eylem-devre-disi notr 200 #d3d6d9
eylem-devre-disi-uzeri notr 500 #757e8a
odak-halkasi ana 600 #275ea5
basari-zemin basari 100 #dff6e9
basari-metin basari 800 #195733
uyari-zemin uyari 100 #fcefd9
uyari-metin uyari 800 #684508
hata-zemin hata 100 #f8e0dd
hata-metin hata 700 #852819
on plan zemin kontrast esik sonuc
metin-birincil yuzey 15.74:1 4.5 gecti
metin-birincil yuzey-ikincil 14.70:1 4.5 gecti
metin-ikincil yuzey 5.89:1 4.5 gecti
metin-ucuncul yuzey 4.11:1 4.5 KALDI
metin-birincil yuzey-secili 12.82:1 4.5 gecti
kenarlik yuzey 4.11:1 3.0 gecti
eylem-ana yuzey 6.50:1 3.0 gecti
eylem-ana-uzeri eylem-ana 6.50:1 4.5 gecti
eylem-ana-uzeri eylem-ana-uzerine 9.05:1 4.5 gecti
eylem-ana-uzeri eylem-ana-basili 12.68:1 4.5 gecti
eylem-devre-disi-uzeri eylem-devre-disi 2.82:1 - olcut yok
odak-halkasi yuzey 6.50:1 3.0 gecti
basari-metin basari-zemin 7.54:1 4.5 gecti
uyari-metin uyari-zemin 7.57:1 4.5 gecti
hata-metin hata-zemin 7.21:1 4.5 gecti
esigi gecemeyen eslesme: 1 / 14
durum rolu taban rol kontrast esik sonuc
eylem-ana-uzerine eylem-ana 1.393 1.2 gecti
eylem-ana-basili eylem-ana-uzerine 1.401 1.2 gecti
eylem-devre-disi yuzey 1.459 1.2 gecti
yuzey-secili yuzey 1.228 1.2 gecti
yuzey-ikincil yuzey 1.071 1.2 KALDI
notr basamak yuzeye karsi 4.5 esigi 3.0 esigi (buyuk metin)
300 1.91 KALDI KALDI
400 2.74 KALDI KALDI
500 4.11 KALDI gecti
600 5.89 gecti gecti
700 8.39 gecti gecti
notr basamak yuzeye karsi 1.2 ayrim esigi uzerindeki metin-ikincil
050 1.071 KALDI 5.51:1 gecti
100 1.204 gecti 4.90:1 gecti
200 1.459 gecti 4.04:1 KALDI
300 1.912 gecti 3.08:1 KALDI
koyu tema karsiligi tanimli rol: 8 / 20
koyu karsiligi eksik roller:
yuzey-secili
metin-ucuncul
eylem-ana-uzerine
eylem-ana-basili
eylem-devre-disi
eylem-devre-disi-uzeri
odak-halkasi
basari-zemin
basari-metin
uyari-zemin
uyari-metin
hata-zemin
koyu temada denetlenebilen eslesmeler
metin-birincil yuzey 15.74:1 4.5 gecti
metin-birincil yuzey-ikincil 11.80:1 4.5 gecti
metin-ikincil yuzey 5.89:1 4.5 gecti
kenarlik yuzey 4.15:1 3.0 gecti
eylem-ana yuzey 6.50:1 3.0 gecti
eylem-ana-uzeri eylem-ana 6.50:1 4.5 gecti
denetlenen: 6 / 14
Üçüncü Metin Düzeyi Renkte Kurulamıyor
Sözleşme denetimi on dört ölçütlü eşleşmeden birini düşürüyor: metin-ucuncul rolü yüzeye
karşı 4.11:1 kontrast üretiyor ve 4.5 eşiğini geçemiyor.
Üçüncü tablo düzeltmenin seçeneklerini veriyor. Nötr ailede 4.5 eşiğini geçen ilk basamak
600; ama 600 zaten metin-ikincil rolünün basamağıdır. Yani üçüncü metin düzeyi, ikinci
düzeyle aynı renge oturmadan bu ölçekte var olamaz.
Bu bulgu Görsel Hiyerarşi dersindeki iki kanal kuralının doğrudan sonucudur. Renk kanalı üç düzey taşıyamıyorsa, üçüncü düzey başka bir kanalda kurulur: boyut, ağırlık ya da konum. Tipografik Ölçek dersinde üstveri düzeyi zaten hem boyutta hem kontrastta ayrılmıştı; renk tarafında üçüncü bir ton eklemeye gerek yoktur.
Tablonun son sütunu bir başka yol daha gösteriyor: nötr 500 basamağı büyük metin için geçerli olan 3.0 eşiğini geçiyor. Üçüncü düzey yalnızca büyük metinde kullanılacaksa rol korunabilir; ancak bu, rolün adına bir koşul eklemeyi gerektirir. Koşullu bir rol, koşulu sözleşmede yazılı olmadığı sürece kullanılmamalıdır — çünkü onu kullanan bileşen koşulu bilmez.
İkincil Yüzey Bir Ayrım Üretmiyor
Durum türevi tablosu ikinci bulguyu veriyor ve bu bulgu ilkinden daha sessizdir. Dört durum
rolü ayrım eşiğini geçiyor: üzerine gelme 1.393, basılı 1.401, devre dışı 1.459, seçili
1.228. Beşincisi geçemiyor: yuzey-ikincil rolü yüzeye karşı yalnız 1.071 kontrast üretiyor.
Bu, arayüzde ikinci bir yüzey düzeyi olduğu varsayılarak yazılmış her kuralın karşılıksız olduğu anlamına gelir. Bir yan panel, bir tablo başlığı ya da bir kart zemininin nötr 050 ile ayrıldığı yerlerde ayrım gerçekte yoktur; ölçek adımı harcanmış, görsel sonuç üretilmemiştir. Yinelenme ve Tutarlılık dersindeki karşılıksız çeşitlilik kavramının renk tarafındaki karşılığı budur.
Son tablo düzeltmeyi ölçüyor ve bir ödünleşim gösteriyor. Nötr 100 ayrım eşiğini geçen ilk basamak (1.204) ve üzerindeki ikincil metin hâlâ 4.90:1 ile eşiği geçiyor. Nötr 200’e çıkıldığında yüzey ayrımı güçleniyor (1.459) ama ikincil metin 4.04’e düşüp eşiği kaybediyor.
Buradan sistem düzeyinde bir kural çıkar: bir yüzey rolünün koyulaştırılması, üzerindeki bütün metin rollerinin yeniden denetlenmesini gerektirir. Yüzey tek başına bir karar değildir; üzerine düşen her rolle birlikte bir karardır. Sözleşmenin işi tam olarak bu bağımlılığı görünür kılmaktır.
Ölçütsüz Eşleşme de Bir Karardır
Devre dışı eylemin metni zeminine karşı 2.82:1 kontrast taşıyor ve tabloda “ölçüt yok” yazıyor. Bu satır sözleşmenin en çok yanlış anlaşılan parçasıdır.
Ölçütün yokluğu bir ihmal değil, yazılmış bir karardır. Devre dışı bir denetim etkileşime kapalıdır ve erişilebilirlik ölçütleri bu durumu kontrast koşulundan muaf tutar. Muafiyetin sözleşmede açıkça yazılması iki iş görür: denetim aracı o satırı hata olarak bildirmez ve okuyan kişi bunun unutulmuş bir denetim olmadığını görür.
Bunun bedeli de kayda geçirilir. Devre dışı bir düğmenin neden devre dışı olduğu renkle anlaşılamaz; düşük kontrast tek başına bir bilgi taşımaz. Mikro Metin dersindeki kural burada tekrarlanır: durumun gerekçesi metinle verilir. Sözleşmenin ölçüt yazmadığı yerde başka bir sözleşme devreye girer.
Sözleşme Her Temada Yeniden Çalışır
Son iki blok bu dersin sistem düzeyindeki asıl bulgusunu veriyor. Yirmi rolün yalnız sekizinin koyu tema karşılığı tanımlı; on ikisi eksik. Sözleşmenin on dört ölçütlü eşleşmesinden yalnız altısı koyu temada denetlenebiliyor.
Denetlenebilen altı eşleşmenin hepsi geçiyor — Koyu Tema dersinde korunum hesabıyla türetildikleri için bu beklenen sonuçtur. Sorun geçen eşleşmelerde değil, denetlenemeyen sekiz eşleşmededir. Koyu temada bir seçili yüzey rolü yoktur; bileşenler o rolü kullandığında tanımsız bir belirtece başvururlar ve önceki dersteki tanımsız başvuru kusuru oluşur.
Bu, eksikliğin nasıl bulunacağını da gösteriyor: rol kümesi ile tema kümesinin çarpımı üzerinden gidilir. Yirmi rol ve iki tema kırk hücre demektir; on ikisi boştur. Rapor üretilmediğinde bu boşluklar ancak kullanıcı koyu temaya geçtiğinde ortaya çıkar.
İşlevsel renklerin tamamının eksik olması ayrıca dikkat çekicidir. Başarı, uyarı ve hata çiftleri açık temada tanımlanmış ve denetlenmiştir; koyu temada hiçbiri yok. İşlevsel renkler en az kullanılan ama en kritik anlarda görünen rollerdir; eksiklikleri en geç fark edilir.
Sözleşmenin Yazılı Biçimi
Roller ve eşleşmeler ayrı dosyalarda durur. Roller biçemde özel özellik olarak, eşleşmeler denetimin okuduğu bir veri dosyası olarak yazılır.
:root { /* ilkel */ --notr-000: #ffffff; --notr-100: #e9eaec; --notr-600: #5e656e; --notr-900: #212327; --ana-600: #275ea5; --ana-700: #1e4980; --ana-800: #15335b; /* anlamsal */ --yuzey: var(--notr-000); --yuzey-ikincil: var(--notr-100); --metin-birincil: var(--notr-900); --metin-ikincil: var(--notr-600); --eylem-ana: var(--ana-600); --eylem-ana-uzerine: var(--ana-700); --eylem-ana-basili: var(--ana-800); --eylem-ana-uzeri: var(--notr-000); }
Eşleşme sözleşmesinin biçemde karşılığı yoktur ve olmamalıdır. CSS bir kontrast oranı hesaplayamaz; sözleşme ancak derleme zamanında ya da sınama aşamasında çalışan bir denetim tarafından okunabilir. Bu, belirteç sisteminin biçemden bağımsız bir veri katmanı olmasının başlıca gerekçesidir: değerler biçeme dönüşür, kurallar denetime.
İkinci ayrıntı, yuzey-ikincil rolünün nötr 050 yerine nötr 100’e taşınmış olmasıdır.
Denetim bu düzeltmeyi zorunlu kıldı; yazılı biçim düzeltilmiş hâli taşır. Denetimin bulduğu
bir kusurun kaynakta düzeltilmemesi, denetimi bir rapor üreticisine indirger.
Özet
- Renk belirteci bir ad ve bir değerden ibaret değildir; hangi zeminlerin üzerine düşebileceği ve hangi eşiği geçmesi gerektiği tanımın parçasıdır.
- Eşleşme listesi bir sözleşmedir: sözleşmede olmayan ön plan–zemin birleşimi tercih değil ihlaldir, ve sözleşme her tema için yeniden çalıştırılır.
- Ölçek her rolü karşılayamaz: üçüncü metin düzeyi bu ölçekte kurulamıyor (nötr 500 eşiği geçemiyor, nötr 600 ikinci düzeyle çakışıyor) ve ikincil yüzey nötr 050’de 1.071 kontrastla ayrılamıyor. Karşılanamayan rol boyut ya da ağırlık kanalına taşınır; yüzeyin koyulaştırılması ise üzerindeki bütün metin rollerinin yeniden denetlenmesini gerektirir.
- Ölçütsüz eşleşme yazılmış bir karardır; muafiyet sözleşmede açıkça belirtilir ve taşıdığı bilgi eksikliği metinle karşılanır.
- Yirmi rolün koyu tema karşılığı yalnız sekizinde tanımlı; ölçütlü on dört eşleşmenin altısı denetlenebiliyor. Eksik hücreler rol ve tema kümesinin çarpımından bulunur.
- Değerler biçeme, kurallar denetime dönüşür; CSS kontrast oranı hesaplayamadığı için sözleşme biçemin dışında yaşar.
Sonraki Adım
Renk tarafında sözleşme, eşleşme kavramıyla kuruldu: bir rolün doğruluğu tek başına değil, başka bir rolle birlikte ölçülüyordu. Tipografi tarafında bağımlılık başka bir biçim alır. Bir metin düzeyi tek bir sayı değildir: boyut, satır yüksekliği, ağırlık ve harf aralığı birlikte bir karar oluşturur ve bu dördü ayrı belirteçlere dağıtıldığında yanlış birleşimler kurulabilir. Sonraki ders tipografi belirteçlerini bileşik belirteç olarak tanımlar, satır kutusu yüksekliklerini aralık ızgarasına oturtur ve düzeylerin ayrım eşiğini denetler.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.