Ders 12 / 22
Tipografik Ölçek
Boyut basamaklarının bir taban ve bir orandan türetilmesi, yuvarlamanın komşu basamak oranını nasıl bozduğu, basamak bütçesinin hesabı ve düzeylerin basamaklara yerleştirilmesi.
İçindekiler
Önceki ders gövde metninin taban boyutunu bir yazı tipi kararına bağladı ve aynı görünen büyüklüğün ailelere göre farklı nominal boyutlar gerektirdiğini hesapladı. Ancak arayüzde tek bir boyut yoktur. Katalog arayüzü en az beş metin düzeyi taşıyor: sayfa başlığı, kayıt başlığı, ödünç alma düğmesinin metni, yazar adı ve üstveri. Bu beş sayı tek tek seçilirse ne olur?
Olan şudur: sayılar birbirinden bağımsız seçilir, aralarındaki oranlar rastgele çıkar ve Görsel Hiyerarşi dersinde konan 1.15 boyut oranı eşiği kimi çiftte tesadüfen tutturulur, kimi çiftte kaçırılır. Ölçek, bu tesadüfü ortadan kaldıran yapıdır: boyutlar tek tek seçilmez, bir tabandan ve bir orandan türetilir.
Ölçek Bir Üstel Dizidir
Tipografik ölçek (typographic scale), bir taban boyuttan başlayarak sabit bir oranla
çarpılan ya da bölünen boyut basamakları dizisidir. n numaralı basamağın boyutu şu
biçimde yazılır:
Burada taban boyut, ölçek oranı, ise basamak numarasıdır. Taban basamağı sıfır kabul edilir; pozitif basamaklar büyür, negatif basamaklar küçülür. Ölçeğin verdiği güvence şudur: herhangi iki komşu basamağın oranı sabittir ve değerine eşittir. Ayrımı denetlemek için tek bir sayıya bakmak yeterli olur.
Bu yapı M14/K02 CSS ile Görsel Sunum kursunda modüler ölçek adıyla tanıtılmıştı; orada sorun bir bildirim yazma sorunuydu. Burada sorun karar sorunudur: hangi oran, kaç basamak ve hangi düzey hangi basamağa.
Yuvarlama Sabit Oranı Bozar
Formül sürekli bir dizi üretir; ekran ise metni tam sayı piksel değerlerinde daha kararlı çizer. Aradaki fark önemsiz görünür ama komşu basamak oranını doğrudan bozar.
// olcek.mjs — oran tabanli tipografik olcek uretimi ve yuvarlamanin ayrima etkisi const TABAN = 16; // govde metni boyutu (px) const ADIMLAR = [-2, -1, 0, 1, 2, 3, 4]; const ORANLAR = [1.125, 1.200, 1.250, 1.333]; const ESIK = 1.15; // Gorsel Hiyerarsi dersinde konan boyut orani esigi function olcek(oran) { return ADIMLAR.map((n) => { const ham = TABAN * Math.pow(oran, n); return { n, ham, yuvarlanmis: Math.round(ham) }; }); } for (const oran of ORANLAR) { const s = olcek(oran); console.log(`\n--- oran ${oran.toFixed(3)} ---`); console.log("adim ham (px) yuvarlanmis komsu orani (ham) komsu orani (yuv) esik"); for (let i = 0; i < s.length; i++) { const a = s[i]; if (i === 0) { console.log( `${String(a.n).padStart(4)} ${a.ham.toFixed(3).padStart(10)} ${String(a.yuvarlanmis).padStart(12)}` + `${"-".padStart(20)}${"-".padStart(19)}${"-".padStart(6)}` ); continue; } const onceki = s[i - 1]; const hamOran = a.ham / onceki.ham; const yuvOran = a.yuvarlanmis / onceki.yuvarlanmis; console.log( `${String(a.n).padStart(4)} ${a.ham.toFixed(3).padStart(10)} ${String(a.yuvarlanmis).padStart(12)}` + `${hamOran.toFixed(4).padStart(20)}${yuvOran.toFixed(4).padStart(19)}` + `${(yuvOran >= ESIK ? "gecti" : "KALDI").padStart(8)}` ); } }
--- oran 1.125 --- adim ham (px) yuvarlanmis komsu orani (ham) komsu orani (yuv) esik -2 12.642 13 - - - -1 14.222 14 1.1250 1.0769 KALDI 0 16.000 16 1.1250 1.1429 KALDI 1 18.000 18 1.1250 1.1250 KALDI 2 20.250 20 1.1250 1.1111 KALDI 3 22.781 23 1.1250 1.1500 gecti 4 25.629 26 1.1250 1.1304 KALDI --- oran 1.200 --- adim ham (px) yuvarlanmis komsu orani (ham) komsu orani (yuv) esik -2 11.111 11 - - - -1 13.333 13 1.2000 1.1818 gecti 0 16.000 16 1.2000 1.2308 gecti 1 19.200 19 1.2000 1.1875 gecti 2 23.040 23 1.2000 1.2105 gecti 3 27.648 28 1.2000 1.2174 gecti 4 33.178 33 1.2000 1.1786 gecti --- oran 1.250 --- adim ham (px) yuvarlanmis komsu orani (ham) komsu orani (yuv) esik -2 10.240 10 - - - -1 12.800 13 1.2500 1.3000 gecti 0 16.000 16 1.2500 1.2308 gecti 1 20.000 20 1.2500 1.2500 gecti 2 25.000 25 1.2500 1.2500 gecti 3 31.250 31 1.2500 1.2400 gecti 4 39.063 39 1.2500 1.2581 gecti --- oran 1.333 --- adim ham (px) yuvarlanmis komsu orani (ham) komsu orani (yuv) esik -2 9.005 9 - - - -1 12.003 12 1.3330 1.3333 gecti 0 16.000 16 1.3330 1.3333 gecti 1 21.328 21 1.3330 1.3125 gecti 2 28.430 28 1.3330 1.3333 gecti 3 37.897 38 1.3330 1.3571 gecti 4 50.517 51 1.3330 1.3421 gecti
Birinci ölçek başarısız. Oranı 1.125 seçmek, eşiğin (1.15) altında bir ayrım seçmek demektir; yuvarlama bunu ne düzeltir ne de kötüleştirir, yalnızca düzensizleştirir. Gerçekleşen oranlar 1.0769 ile 1.1500 arasında salınıyor: bir basamak çiftinde artış yüzde 7.7, başka bir çiftte yüzde 15, yani tam iki katı. Ölçeğin verdiği tek güvence — komşu oranın sabit olması — yuvarlamayla birlikte kayboluyor.
Küçük boyutlarda salınımın büyümesi tesadüf değil. Yuvarlama hatası en çok bir yarım pikseldir; bu hatanın orana etkisi boyutla ters orantılıdır. 13 pikselde yarım piksel yüzde 3.8’lik bir sapma, 39 pikselde yüzde 1.3’lük bir sapmadır. Ölçeğin alt ucu, üst ucundan üç kat daha kırılgandır.
Diğer üç ölçekte yuvarlanmış oranların hepsi eşiği geçiyor. Oran büyüdükçe salınımın etkisi de göreli olarak küçülüyor: 1.333 oranlı ölçekte gerçekleşen oranlar 1.3125 ile 1.3571 arasında, yani en geniş oran en darının 1.034 katı.
Buradan çıkan kural şu biçimde yazılabilir: ölçek oranı, ayrım eşiğinden belirgin biçimde büyük seçilir. Eşiğe eşit ya da yakın bir oran, yuvarlamanın hangi yönde çalıştığına göre kimi basamak çiftinde eşiğin altına düşer.
Basamak Bütçesi
Oranı büyütmenin bir bedeli vardır. Arayüzün kullanabileceği boyut aralığı sınırlıdır: alt ucu okunabilirlik, üst ucu ekranda kapladığı yer belirler. Oran büyüdükçe bu aralığa daha az basamak sığar.
// basamak.mjs — olcegin basamak butcesi ve duzeylerin basamaklara yerlestirilmesi const TABAN = 16; const EN_KUCUK = 12; // altina inilmeyecek govde-disi metin boyutu const EN_BUYUK = 40; // katalog arayuzunde gereken en buyuk baslik boyutu console.log("oran basamak sayisi (12-40 px arasi) ilk basamak son basamak"); for (const oran of [1.125, 1.2, 1.25, 1.333, 1.5]) { const altAdim = Math.ceil(Math.log(EN_KUCUK / TABAN) / Math.log(oran)); const ustAdim = Math.floor(Math.log(EN_BUYUK / TABAN) / Math.log(oran)); const sayi = ustAdim - altAdim + 1; const ilk = Math.round(TABAN * Math.pow(oran, altAdim)); const son = Math.round(TABAN * Math.pow(oran, ustAdim)); console.log( `${oran.toFixed(3)} ${String(sayi).padStart(28)} ${String(ilk).padStart(12)} ${String(son).padStart(12)}` ); } // Katalog arayuzunun duzeyleri, 1.25 oranli olcegin basamaklarina yerlestirildi. const ORAN = 1.25; const boyut = (n) => Math.round(TABAN * Math.pow(ORAN, n)); const duzeyler = [ { ad: "sayfa basligi", adim: 3, agirlik: 700 }, { ad: "kayit basligi", adim: 1, agirlik: 600 }, { ad: "dugme metni", adim: 0, agirlik: 600 }, { ad: "yazar", adim: 0, agirlik: 400 }, { ad: "ustveri", adim: -1, agirlik: 400 }, ]; const ESIK = { boyutOrani: 1.15, agirlikFarki: 200 }; console.log("\nduzey adim boyut(px) agirlik"); for (const d of duzeyler) { console.log( `${d.ad.padEnd(15)} ${String(d.adim).padStart(4)} ${String(boyut(d.adim)).padStart(9)} ${String(d.agirlik).padStart(8)}` ); } console.log("\nkomsu duzey cifti boyut orani agirlik farki gecen kanal"); for (let i = 0; i < duzeyler.length - 1; i++) { const ust = duzeyler[i]; const alt = duzeyler[i + 1]; const bOran = boyut(ust.adim) / boyut(alt.adim); const aFark = ust.agirlik - alt.agirlik; const gecen = []; if (bOran >= ESIK.boyutOrani) gecen.push("boyut"); if (aFark >= ESIK.agirlikFarki) gecen.push("agirlik"); const etiket = `${ust.ad} > ${alt.ad}`; console.log( `${etiket.padEnd(31)} ${bOran.toFixed(3).padStart(11)} ${String(aFark).padStart(14)} ${gecen.length ? gecen.join("+") : "ZAYIF"}` ); }
oran basamak sayisi (12-40 px arasi) ilk basamak son basamak 1.125 10 13 36 1.200 7 13 40 1.250 6 13 39 1.333 5 12 38 1.500 3 16 36 duzey adim boyut(px) agirlik sayfa basligi 3 31 700 kayit basligi 1 20 600 dugme metni 0 16 600 yazar 0 16 400 ustveri -1 13 400 komsu duzey cifti boyut orani agirlik farki gecen kanal sayfa basligi > kayit basligi 1.550 100 boyut kayit basligi > dugme metni 1.250 0 boyut dugme metni > yazar 1.000 200 agirlik yazar > ustveri 1.231 0 boyut
Birinci tablo ölçek oranı seçiminin gerçek ödünleşimini gösteriyor. Aynı 12–40 piksel aralığına 1.125 oranıyla on basamak, 1.5 oranıyla üç basamak sığıyor. Bir önceki hesap 1.125 oranının eşiği tutturamadığını göstermişti; bu tablo da 1.5 oranının yalnızca üç düzeye yer bıraktığını gösteriyor. Katalog arayüzü beş düzey istiyor, dolayısıyla 1.5 oranı doğrudan elenir. Kalan aday 1.2, 1.25 ve 1.333; hepsi eşiği geçiyor ve hepsi beş düzeye yetiyor.
Karar 1.25 oranıyla verildi. Gerekçe, ikinci tablodaki boşluktur: altı basamak, beş düzey için bir basamaklık pay bırakır. Ölçeğin dolu olması, sonradan bir düzey eklenmesi gerektiğinde ölçeğin tamamının yeniden hesaplanması demektir.
Her Düzey Yeni Bir Basamak İstemez
Üçüncü tablodaki düzey yerleşiminde iki nokta dikkat çekiyor.
Birincisi, düğme metni ile yazar adı aynı basamakta duruyor: ikisi de sıfırıncı basamak, 16 piksel. Boyut oranı 1.000; boyut kanalı ayrım üretmiyor. Ayrım ağırlıkta kuruluyor ve 200 birimlik fark eşiği geçiyor. Görsel Hiyerarşi dersindeki iki kanal kuralı burada üçüncü bir kanalla karşılanıyor: düğme metni dolgulu bir yüzeyin üzerinde duruyor, yazar adı düz zeminde. Yüzey, bu tabloda görünmeyen ama gerçekte çalışan bir kanaldır ve Renk Sistemi dersinin konusudur.
İkincisi, dördüncü satırdaki karşılaştırma aslında hiyerarşik bir çift değil. Düğme metni ile yazar adı aynı görsel alanda yarışmaz; biri eylem bölgesinde, diğeri kayıt satırının içindedir. Komşuluk denetimi düzeyleri sıralı bir liste sanar; hiyerarşi ise yalnızca aynı anda görülen ögeler arasında anlamlıdır. Tablo bir uyarı üretmediği için bu ayrım sorun çıkarmadı, ancak “ZAYIF” çıkan bir satırın gerçek bir sorun olup olmadığı her zaman bu soruyla denetlenir.
Son satır ise ilk dersteki bir bulgunun kapanışıdır. Yazar ile üstveri arasındaki ayrım o derste yalnız kontrast kanalında duruyordu ve tek bacaklı sayılmıştı. Ölçek, üstveriyi 14 yerine 13 piksele indirerek boyut oranını 1.231’e çıkardı; artık ayrım hem boyutta hem kontrastta duruyor. Basamak kararı, tek tek boyut seçmenin çözemediği bir sorunu ölçeğin kendi yapısıyla çözdü.
Ölçeğin Yazılı Biçimi
Ölçek bir hesap olarak kalırsa her kullanımda yeniden yapılır ve sapar. Yazılı biçimi, basamakların adlandırılmış değerlere dönüştürülmesidir:
:root { --boyut--1: 13px; --boyut-0: 16px; --boyut-1: 20px; --boyut-2: 25px; --boyut-3: 31px; }
Adların basamak numarasını taşıması, “başlık” ya da “küçük” gibi anlam taşımasından daha dayanıklıdır. Anlam taşıyan adlar arayüz değiştiğinde yalan söylemeye başlar: “başlık” adlı değer bir gün başlık olmayan bir yerde kullanılır. Basamak numarası ise yalnızca ölçekteki konumu bildirir ve o konum değişmez.
Bu listede ara değer yoktur ve olmamalıdır. Bir düzey için 18 piksel gerektiği hissi doğduğunda yanıt yeni bir değişken eklemek değil, düzeyin hangi basamağa ait olduğuna karar vermektir. Ölçeğin dışına çıkan her sayı, ölçeğin verdiği güvenceyi o noktada iptal eder.
Özet
- Tipografik ölçek, boyutları bir taban ve bir orandan üstel olarak türetir; sağladığı güvence, komşu basamak oranının sabit olmasıdır.
- Tam sayı piksele yuvarlama bu sabitliği bozar; sapmanın orana etkisi küçük boyutlarda büyüktür, dolayısıyla ölçeğin alt ucu en kırılgan yeridir.
- Ölçek oranı ayrım eşiğine eşit değil, ondan belirgin biçimde büyük seçilir; eşiğe yakın oran kimi basamak çiftinde yuvarlamayla eşiğin altına düşer.
- Oran büyüdükçe verilen boyut aralığına sığan basamak sayısı azalır; oran seçimi ayrım gücü ile basamak bütçesi arasındaki ödünleşimdir.
- Her düzey yeni bir basamak istemez; aynı basamaktaki iki düzey ağırlık ya da yüzey kanalında ayrılabilir.
- Ölçek adlandırılmış basamak değerleri olarak yazılır; ara değer eklemek, ölçeğin verdiği güvenceyi o noktada iptal eder.
Sonraki Adım
Ölçek metnin ne kadar büyük olacağını söyledi, ne kadar geniş olacağını değil. Bir kayıt ayrıntısındaki özet paragrafı sütunun tamamına yayıldığında satırlar uzar ve göz satır sonundan bir sonraki satırın başına dönerken hedefi kaçırmaya başlar. Sonraki ders satır uzunluğunu karakter cinsinden hesaplar, ölçüyü sütun genişliğine bağlar ve satır aralığının neden satır uzunluğuyla birlikte ayarlanması gerektiğini gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.