Ders 18 / 26
Saydamlık ve Karışım
Alfa kanalının harmanlama hesabı, opacity ile alfa arasındaki fark ve harmanlanmış rengin kontrast oranının WCAG ölçütlerine göre değerlendirilmesi.
İçindekiler
Önceki derste renkler tam donuk kabul edildi ve sekiz basamaklı onaltılık yazımda görülen alfa kanalı açıklanmadan geçildi. Saydam bir renk bir zeminin üzerine bindiğinde ortaya çıkan renk nedir?
Bu sorunun yanıtı bir hesaptır ve hesabın sonucu okunabilirliği doğrudan etkiler. Saydamlaştırılmış bir metin rengi, zeminle karışarak beklenenden soluk bir renge dönüşür ve kontrast oranı düşer. Bu ders harmanlama hesabını ve kontrast oranını sayıyla ele alır.
Alfa Harmanlaması
Alfa kanalı (alpha channel) bir rengin ne kadar donuk olduğunu bildirir: 1 tam donuk, 0 tam saydam. Saydam bir renk zeminin üzerine bindiğinde her bileşen için ağırlıklı ortalama alınır:
Kontrast oranı ise WCAG’de tanımlıdır. Önce her rengin bağıl parlaklığı (relative luminance) hesaplanır — kanallar doğrusallaştırılır ve göz duyarlılığına göre ağırlıklı toplanır — sonra iki parlaklık şu bağıntıya sokulur:
Sonuç 1:1 (aynı renk) ile 21:1 (siyah–beyaz) arasında bir sayıdır.
// harman.mjs — alfa harmanlamasi ve WCAG kontrast orani const hexToRgb = (hex) => { let h = hex.replace("#", ""); if (h.length === 3) h = [...h].map((c) => c + c).join(""); return { r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16) }; }; // ustteki renk alfa ile alttakinin uzerine harmanlanir: C = a*Cu + (1-a)*Ca function harmanla(ust, alfa, alt) { const u = hexToRgb(ust), a = hexToRgb(alt); const k = (x, y) => Math.round(alfa * x + (1 - alfa) * y); return { r: k(u.r, a.r), g: k(u.g, a.g), b: k(u.b, a.b) }; } const hex = ({ r, g, b }) => "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join(""); // WCAG 2 bagil parlaklik function bagilParlaklik({ r, g, b }) { const kanal = (v) => { const s = v / 255; return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); }; return 0.2126 * kanal(r) + 0.7152 * kanal(g) + 0.0722 * kanal(b); } // kontrast orani: (L1 + 0.05) / (L2 + 0.05), L1 >= L2 function kontrast(a, b) { const la = bagilParlaklik(a), lb = bagilParlaklik(b); const [ust, alt] = la > lb ? [la, lb] : [lb, la]; return (ust + 0.05) / (alt + 0.05); } console.log("--- alfa harmanlamasi (zemin #ffffff) ---"); for (const alfa of [1, 0.8, 0.5, 0.2, 0]) { const s = harmanla("#143a52", alfa, "#ffffff"); console.log(`alfa=${alfa.toFixed(2)} -> rgb(${s.r} ${s.g} ${s.b}) = ${hex(s)}`); } console.log("\n--- ayni renk koyu zeminde (#1c2733) ---"); for (const alfa of [1, 0.8, 0.5, 0.2]) { const s = harmanla("#143a52", alfa, "#1c2733"); console.log(`alfa=${alfa.toFixed(2)} -> ${hex(s)}`); } console.log("\n--- kontrast oranlari ---"); const ciftler = [ ["#1c2733", "#ffffff"], ["#1c2733", "#f5f7f8"], ["#143a52", "#ffffff"], ["#8a1c1c", "#ffffff"], ["#8a5b00", "#ffffff"], ["#6b767f", "#ffffff"], ["#d5dbe0", "#ffffff"], ["#ffffff", "#143a52"], ]; for (const [on, arka] of ciftler) { const o = kontrast(hexToRgb(on), hexToRgb(arka)); const normal = o >= 7 ? "AAA" : o >= 4.5 ? "AA" : "gecmez"; const buyuk = o >= 4.5 ? "AAA" : o >= 3 ? "AA" : "gecmez"; console.log(`${on} / ${arka} -> ${o.toFixed(2)}:1 normal metin ${normal.padEnd(6)} buyuk metin ${buyuk}`); } console.log("\n--- saydam metnin kontrasti ---"); for (const alfa of [1, 0.7, 0.5, 0.35]) { const s = harmanla("#1c2733", alfa, "#ffffff"); const o = kontrast(s, hexToRgb("#ffffff")); console.log(`alfa=${alfa.toFixed(2)} -> ${hex(s)} kontrast ${o.toFixed(2)}:1 ${o >= 4.5 ? "AA gecer" : "AA gecmez"}`); }
--- alfa harmanlamasi (zemin #ffffff) --- alfa=1.00 -> rgb(20 58 82) = #143a52 alfa=0.80 -> rgb(67 97 117) = #436175 alfa=0.50 -> rgb(138 157 169) = #8a9da9 alfa=0.20 -> rgb(208 216 220) = #d0d8dc alfa=0.00 -> rgb(255 255 255) = #ffffff --- ayni renk koyu zeminde (#1c2733) --- alfa=1.00 -> #143a52 alfa=0.80 -> #16364c alfa=0.50 -> #183143 alfa=0.20 -> #1a2b39 --- kontrast oranlari --- #1c2733 / #ffffff -> 15.14:1 normal metin AAA buyuk metin AAA #1c2733 / #f5f7f8 -> 14.09:1 normal metin AAA buyuk metin AAA #143a52 / #ffffff -> 11.95:1 normal metin AAA buyuk metin AAA #8a1c1c / #ffffff -> 9.28:1 normal metin AAA buyuk metin AAA #8a5b00 / #ffffff -> 5.87:1 normal metin AA buyuk metin AAA #6b767f / #ffffff -> 4.64:1 normal metin AA buyuk metin AAA #d5dbe0 / #ffffff -> 1.40:1 normal metin gecmez buyuk metin gecmez #ffffff / #143a52 -> 11.95:1 normal metin AAA buyuk metin AAA --- saydam metnin kontrasti --- alfa=1.00 -> #1c2733 kontrast 15.14:1 AA gecer alfa=0.70 -> #606870 kontrast 5.66:1 AA gecer alfa=0.50 -> #8e9399 kontrast 3.10:1 AA gecmez alfa=0.35 -> #b0b3b8 kontrast 2.10:1 AA gecmez
Harmanlama Zemine Bağlıdır
Çıktının ilk iki bloğu aynı rengi iki farklı zemin üzerinde harmanlıyor. #143a52 rengi
0.5 alfayla beyaz zeminde #8a9da9’a, koyu zeminde #183143’e dönüştü. İki sonuç
birbirine benzemez.
Sonuç şudur: saydam bir renk sabit bir renk değildir. Bir bileşene saydam bir arka plan verildiğinde, bileşenin görünümü nereye konduğuna bağlı olur. Bu bazen istenen davranıştır — bir gölge ya da örtü katmanı zeminle uyum sağlamalıdır. Bazen değildir: bir uyarı rozetinin rengi bulunduğu yere göre değişmemelidir.
Çıktının son satırı bir sınır durumunu gösteriyor: alfa sıfır olduğunda sonuç tamamen zemin
rengidir. transparent anahtar sözcüğü tam olarak bunu ifade eder.
opacity Alfadan Farklıdır
İki mekanizma benzer görünür ama farklı şeyler yapar.
Renk alfası yalnızca o rengin uygulandığı özelliği etkiler.
background-color: rgb(20 58 82 / 0.5) yazmak yalnızca arka planı saydamlaştırır; metin ve
kenarlık donuk kalır.
opacity ögenin tamamını — arka planı, metni, kenarlığı, bütün çocuklarını —
tek bir katman olarak saydamlaştırır. Alt ögelere ayrı ayrı uygulanmaz; öge önce kendi
içinde çizilir, sonra bütün olarak harmanlanır.
Bunun iki sonucu vardır. Birincisi, opacity: 0.5 verilmiş bir kutunun içindeki metnin
saydamlığı iptal edilemez; çocukta opacity: 1 yazmak işe yaramaz. İkincisi, yığılma
bağlamı dersinde gördüğümüz gibi 1’den küçük her opacity değeri bir yığılma bağlamı
kurar — çünkü bütün olarak harmanlama tam da bunu gerektirir.
Uygulanabilir kural: bir rengi saydamlaştırmak isteniyorsa renk alfası yazılır; bir ögenin
tamamını soldurmak isteniyorsa opacity yazılır.
Kontrast Oranını Okumak
Çıktının üçüncü bloğu WCAG ölçütlerine göre değerlendirilmiş oranları veriyor. Ölçütler şunlardır:
| Ölçüt | Normal metin | Büyük metin |
|---|---|---|
| AA | 4,5:1 | 3:1 |
| AAA | 7:1 | 4,5:1 |
Büyük metin, kalın olmayan 24 piksel ya da kalın 18,66 piksel ve üzeri boyuttaki metindir. Metin dışındaki görsel bileşenler — form alanı kenarlıkları, simgeler, odak göstergeleri — için ölçüt 3:1’dir.
Çizelgedeki satırlar üç tür karar veriyor.
#6b767f rengi beyaz üzerinde 4,64:1 veriyor ve AA ölçütünü kıl payı geçiyor. Soluk
metin renkleri bu sınırda dolaşır; bir tonluk bir değişiklik ölçütü düşürebilir.
#d5dbe0 rengi 1,40:1 ile hiçbir ölçütü geçmiyor. Bu renk çizgi rengi olarak seçilmişti ve
metin rengi olarak kullanılamaz. Kenarlık için bile 3:1 ölçütünün altında kalır; ayırıcı
çizgi olarak dekoratif kabul edilebilir ama bir form alanının sınırını göstermek için
yetersizdir.
Son satır simetriyi gösteriyor: #ffffff / #143a52 ve #143a52 / #ffffff aynı oranı
veriyor. Kontrast oranı yönsüzdür; hangisinin ön hangisinin arka plan olduğuna bakmaz.
Saydamlık Kontrastı Düşürür
Çıktının son bloğu bu dersin en pratik sonucudur. Tam donuk #1c2733 metni beyaz zeminde
15,14:1 veriyor. Aynı renk 0,5 alfayla yazıldığında oran 3,10:1’e düşüyor ve AA ölçütünü
geçmiyor.
Bir metni “soluklaştırmak” için alfa kullanmak bu yüzden tehlikelidir: yapılan şey bir görsel ayardan çok, bir okunabilirlik kaybıdır ve kayıp hesaplanmadıkça görünmez. Doğru yol, soluk tonu ölçekten seçmek ve seçilen tonun kontrast oranını hesaplamaktır.
WCAG 2’deki bu hesabın bilinen bir sınırı vardır: bağıl parlaklık, algılanan kontrastı her renk çiftinde aynı doğrulukla yansıtmaz — özellikle koyu zeminlerde ve doygun renklerde sapma gösterir. Ölçüt yine de ölçülebilir ve sınanabilir bir taban sağlar; hesabın geçilmesi gereken bir alt sınır olarak okunur, iyi tasarımın tanımı olarak değil.
/* istasyon.css — 17. adım: saydamlık ve kontrast */ .kaynak-notu { color: hsl(211 12% 45%); } /* donuk ton, alfa değil */ .gorsel-orgusu { background-color: rgb(20 58 82 / 0.08); } .katman-ortusu { position: fixed; inset: 0; background-color: rgb(28 39 51 / 0.6); } .devre-disi { opacity: 0.55; pointer-events: none; }
.kaynak-notu soluk metin için alfa yerine ölçekten seçilmiş donuk bir ton kullanıyor.
.gorsel-orgusu ve .katman-ortusu ise alfayı doğru yerde kullanıyor: ikisi de zeminle
karışması istenen katmanlar.
.devre-disi sınıfı opacity kullanıyor çünkü ögenin tamamının — metni, kenarlığı, arka
planı — birlikte solması isteniyor. pointer-events: none görsel durumun etkileşimle
tutarlı olmasını sağlar; ancak devre dışı bırakma bilgisinin belgede disabled ya da
aria-disabled ile bildirilmesi gerekir. Saydamlık tek başına hiçbir yardımcı teknolojiye
bir şey söylemez.
Özet
- Alfa harmanlaması ağırlıklı ortalamadır: sonuç renk, üst rengin alfayla, alt rengin kalan payla çarpılıp toplanmasıyla bulunur.
- Saydam bir renk sabit bir renk değildir; sonucu zemine bağlıdır ve aynı bildirim iki farklı zeminde iki farklı renk üretir.
- Renk alfası yalnızca o bildirimi etkiler;
opacityögeyi ve bütün çocuklarını tek bir katman olarak saydamlaştırır ve bir yığılma bağlamı kurar. - Kontrast oranı bağıl parlaklıklardan hesaplanır, 1:1 ile 21:1 arasındadır ve yönsüzdür; AA ölçütü normal metin için 4,5:1, büyük metin için 3:1’dir.
- Bir metni alfayla soluklaştırmak kontrast oranını düşürür; soluk ton, hesaplanmış bir donuk renk olarak ölçekten seçilir.
Sonraki Adım
Renk kararları verildi ama metnin kendisine henüz dokunulmadı: hangi yazı tipiyle, hangi boyutta, hangi satır aralığıyla yazılacağı belirlenmedi. Sonraki ders tipografiyi ele alır ve yazı tipi ailesinin nasıl seçildiğini, boyut ölçeğinin nasıl kurulduğunu ve satır yüksekliğinin neden birimsiz yazıldığını hesapla gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.