İçeriğe geç
academia.sh

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:

Csonuc¸=αCu¨st+(1α)CaltC_{\text{sonuç}} = \alpha \cdot C_{\text{üst}} + (1 - \alpha) \cdot C_{\text{alt}}

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:

oran=Lac¸ık+0,05Lkoyu+0,05\text{oran} = \frac{L_{\text{açık}} + 0{,}05}{L_{\text{koyu}} + 0{,}05}

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat