Ders 10 / 23
Duyarlı Tipografi
Akışkan yazı boyutu ifadesinin iki ölçü noktasından türetilmesi, ölçek oranının dar ekranda daralması, satır uzunluğu denetimi ve yazının yakınlaştırma ile kullanıcı ayarına verdiği tepki.
İçindekiler
Bir önceki derste kart yazısı clamp() ifadesinin içine yerleştirildi ve üç sayı verildi: alt
sınır, tercih edilen değer, üst sınır. Sayıların nasıl seçildiği söylenmedi.
Bu ders o seçimi hesaba döker. Yazı boyutunun ölçekle değişmesi bir görsel tercih değil, okunabilirlik kısıtının sonucudur; kısıt sayıya çevrildiğinde ifade kendiliğinden çıkar.
İki Ölçü Noktası, Bir Doğru
Akışkan tipografide (fluid typography) girdi iki karardır: en dar düzende yazının ne
kadar olacağı ve en geniş düzende ne kadar olacağı. İki nokta bir doğru belirler; clamp() ifadesinin orta terimi
bu doğrunun denklemidir.
Doğrunun eğimi görüntü alanı birimiyle, kesişimi taban birimle yazılır. İkisinin toplamı, görüntü alanı büyüdükçe yazının doğrusal büyümesini verir.
// akiskan.mjs — iki olcu noktasindan akiskan yazi boyutu ifadesinin turetilmesi const KOK = 16; // iki olcu noktasi: (gorus alani, istenen yazi boyutu) function turet(v1, s1, v2, s2) { const egim = (s2 - s1) / (v2 - v1); // px / px const vw = egim * 100; // 1vw = gorus alaninin yuzde biri const sabitPx = s1 - egim * v1; // ifadenin sabit terimi return { vw, sabitRem: sabitPx / KOK, sabitPx }; } const govde = turet(360, 16, 1280, 20); const baslik = turet(360, 24, 1280, 40); const yaz = (t, alt, ust) => `clamp(${(alt / KOK).toFixed(3)}rem, ${t.sabitRem.toFixed(4)}rem + ${t.vw.toFixed(4)}vw, ${(ust / KOK).toFixed(3)}rem)`; console.log("olcu noktalari: 360px -> govde 16px / baslik 24px, 1280px -> govde 20px / baslik 40px"); console.log("govde :", yaz(govde, 16, 20)); console.log("baslik :", yaz(baslik, 24, 40)); const clamp = (k, t, b) => Math.max(k, Math.min(t, b)); const coz = (t, alt, ust, gorus) => clamp(alt, t.sabitPx + (t.vw * gorus) / 100, ust); console.log("\ngorus alani govde baslik baslik/govde govde bolgesi"); for (const V of [320, 360, 500, 700, 900, 1280, 1600]) { const g = coz(govde, 16, 20, V); const b = coz(baslik, 24, 40, V); const bolge = g === 16 ? "alt sinir" : g === 20 ? "ust sinir" : "tercih"; console.log( `${String(V).padStart(11)} ${g.toFixed(2).padStart(5)} ${b.toFixed(2).padStart(6)} ` + `${(b / g).toFixed(3).padStart(12)} ${bolge.padStart(13)}`, ); } // olcu denetimi: metin sutunu 675px ust sinirli, karakter genisligi yazi boyutunun yarisi console.log("\n--- satir uzunlugu denetimi (sutun ust siniri 675px, kenar bosluk 48px) ---"); console.log("gorus alani sutun govde karakter 45-75 araliginda mi"); for (const V of [320, 360, 500, 700, 900, 1280, 1600]) { const sutun = Math.min(675, V - 48); const g = coz(govde, 16, 20, V); const karakter = sutun / (g * 0.5); console.log( `${String(V).padStart(11)} ${sutun.toFixed(0).padStart(5)} ${g.toFixed(2).padStart(5)} ` + `${karakter.toFixed(1).padStart(8)} ${(karakter >= 45 && karakter <= 75 ? "evet" : "HAYIR").padStart(19)}`, ); }
olcu noktalari: 360px -> govde 16px / baslik 24px, 1280px -> govde 20px / baslik 40px
govde : clamp(1.000rem, 0.9022rem + 0.4348vw, 1.250rem)
baslik : clamp(1.500rem, 1.1087rem + 1.7391vw, 2.500rem)
gorus alani govde baslik baslik/govde govde bolgesi
320 16.00 24.00 1.500 alt sinir
360 16.00 24.00 1.500 alt sinir
500 16.61 26.43 1.592 tercih
700 17.48 29.91 1.711 tercih
900 18.35 33.39 1.820 tercih
1280 20.00 40.00 2.000 ust sinir
1600 20.00 40.00 2.000 ust sinir
--- satir uzunlugu denetimi (sutun ust siniri 675px, kenar bosluk 48px) ---
gorus alani sutun govde karakter 45-75 araliginda mi
320 272 16.00 34.0 HAYIR
360 312 16.00 39.0 HAYIR
500 452 16.61 54.4 evet
700 652 17.48 74.6 evet
900 675 18.35 73.6 evet
1280 675 20.00 67.5 evet
1600 675 20.00 67.5 evet
İki satırlık çıktı, elle yazılması zor iki ifadeyi veriyor. Gövde yazısı için sabit terim 0,9022 taban birim, eğim 0,4348 görüntü alanı birimi. Sayıların ondalıklı olması beklenendir: iki ölçü noktasından geçen doğrunun katsayıları yuvarlak çıkmaz.
İfade üç bölgede çalışır. 360 biriminin altında alt sınır, 1280 biriminin üstünde üst sınır uygulanır; arada doğru işler. Ölçü noktalarındaki değerler tam olarak istenen sayılardır — bu, türetmenin doğruluk denetimidir.
Ölçek Dar Ekranda Daralır
Dördüncü sütun ayrı bir olguyu ölçüyor: başlık ile gövde arasındaki oran sabit değil.
Dar düzende oran 1,5; geniş düzende 2,0. Bu, iki ayrı ifadenin farklı eğimlere sahip olmasının kaçınılmaz sonucudur ve istenen sonuçtur. Bir başlık, gövde yazısının iki katı olduğunda dar bir ekranda satırı ikiye böler ve hiyerarşi bilgisi yerine bir engel üretir. Aynı oran geniş bir ekranda yerini bulur.
CSS ile Görsel Sunum kursunda tanıtılan modüler ölçek, adımlar arasındaki oranı sabit bir
çarpanla verir. Duyarlı tipografide bu çarpanın kendisi ölçekle değişir: dar düzende sıkışır,
geniş düzende açılır. Uygulamada bu, her ölçek adımı için ayrı bir clamp() ifadesi yazmak
demektir; adımların ifadeleri farklı eğimlere sahip olur.
Bir uyarı: ölçek adımlarının sırası korunmalıdır. İki ifade farklı eğimlerle yazıldığında, belirli bir genişlikte alt adımın üst adımı geçmesi mümkündür. Denetim yolu türetmenin kendisidir — iki uçtaki değerler sıralıysa ve iki ifade de doğrusalsa arada sıra bozulmaz.
Satır Uzunluğu Denetimi
Yazı boyutu tek başına anlam taşımaz; anlamlı olan satır uzunluğudur (line length) — yani satırda kaç karakter bulunduğudur. İkinci tablo bunu denetliyor: sütun genişliği yazı boyutunun yarısına bölünerek karakter sayısı bulunuyor.
Beş genişlikte sonuç aralıkta, iki genişlikte değil. 320 ve 360 birimlik görüntü alanlarında satır 34 ve 39 karakter; alt sınırın altında.
Bu bir hata değil, bir kısıttır. Dar bir ekranda 45 karaktere ulaşmanın tek yolu yazıyı küçültmektir ve yazı zaten alt sınırındadır. İki kısıt aynı anda karşılanamaz; okunabilir yazı boyutu korunur, satır uzunluğu kabul edilir.
Tablonun asıl değeri şudur: kısıt bilinerek kabul edilmiştir. Aynı hesap, üst sınırın aşıldığı durumu da yakalar — 700 birimde satır 74,6 karaktere çıkıyor ve sınıra dayanıyor. Sütunun üst sınırı 675 birim yerine 720 birim seçilseydi bu satır aralığın dışına çıkardı.
Yakınlaştırma ve Kullanıcı Ayarı
Bir yazı boyutu ifadesinin son sınavı, kullanıcının yazıyı büyütme isteğine verdiği tepkidir.
// yakinlastirma.mjs — yazi boyutu ifadesinin yakinlastirmaya ve kullanici ayarina tepkisi const AYGIT = 1280; // aygitin fiziksel genisligi (aygit pikseli) // Yakinlastirma orani Z: 1 CSS pikseli Z aygit pikseli olur, // gorus alani CSS pikseli cinsinden AYGIT/Z olur. function olcum(Z, kok) { const gorusCss = AYGIT / Z; const vwSadece = (1.25 * gorusCss) / 100; // font-size: 1.25vw const remSadece = 1.25 * kok; // font-size: 1.25rem const tercih = 0.9022 * kok + (0.4348 * gorusCss) / 100; // clamp'in orta terimi const kelepce = Math.max(1 * kok, Math.min(tercih, 1.25 * kok)); // clamp(1rem, ..., 1.25rem) return { gorusCss, vwCss: vwSadece, vwAygit: vwSadece * Z, remCss: remSadece, remAygit: remSadece * Z, clampCss: kelepce, clampAygit: kelepce * Z, }; } console.log(`aygit genisligi ${AYGIT} aygit pikseli, kok yazi boyutu 16px\n`); console.log("--- sayfa yakinlastirma: metnin fiziksel boyutu ---"); console.log("yakinlastirma gorus alani(css) 1.25vw 1.25rem clamp <- aygit pikseli"); for (const Z of [1, 1.25, 1.5, 2]) { const o = olcum(Z, 16); console.log( `${(Z * 100 + "%").padStart(13)} ${o.gorusCss.toFixed(0).padStart(16)} ` + `${o.vwAygit.toFixed(2).padStart(6)} ${o.remAygit.toFixed(2).padStart(7)} ${o.clampAygit.toFixed(2).padStart(5)}`, ); } const t1 = olcum(1, 16), t2 = olcum(2, 16); console.log("\n%200 yakinlastirmada buyume orani:"); console.log(` 1.25vw : ${(t2.vwAygit / t1.vwAygit).toFixed(2)}x`); console.log(` 1.25rem : ${(t2.remAygit / t1.remAygit).toFixed(2)}x`); console.log(` clamp : ${(t2.clampAygit / t1.clampAygit).toFixed(2)}x`); console.log("\n--- kullanici varsayilan yazi boyutunu degistirirse (yakinlastirma yok) ---"); console.log("varsayilan 1.25vw 1.25rem clamp <- css pikseli"); for (const kok of [16, 20, 24, 32]) { const o = olcum(1, kok); console.log( `${(kok + "px").padStart(10)} ${o.vwCss.toFixed(2).padStart(6)} ` + `${o.remCss.toFixed(2).padStart(7)} ${o.clampCss.toFixed(2).padStart(5)}`, ); } const k1 = olcum(1, 16), k2 = olcum(1, 32); console.log("\nvarsayilan iki katina cikarildiginda buyume orani:"); console.log(` 1.25vw : ${(k2.vwCss / k1.vwCss).toFixed(2)}x`); console.log(` 1.25rem : ${(k2.remCss / k1.remCss).toFixed(2)}x`); console.log(` clamp : ${(k2.clampCss / k1.clampCss).toFixed(2)}x`);
aygit genisligi 1280 aygit pikseli, kok yazi boyutu 16px
--- sayfa yakinlastirma: metnin fiziksel boyutu ---
yakinlastirma gorus alani(css) 1.25vw 1.25rem clamp <- aygit pikseli
100% 1280 16.00 20.00 20.00
125% 1024 16.00 25.00 23.61
150% 853 16.00 30.00 27.22
200% 640 16.00 40.00 34.44
%200 yakinlastirmada buyume orani:
1.25vw : 1.00x
1.25rem : 2.00x
clamp : 1.72x
--- kullanici varsayilan yazi boyutunu degistirirse (yakinlastirma yok) ---
varsayilan 1.25vw 1.25rem clamp <- css pikseli
16px 16.00 20.00 20.00
20px 16.00 25.00 23.61
24px 16.00 30.00 27.22
32px 16.00 40.00 34.44
varsayilan iki katina cikarildiginda buyume orani:
1.25vw : 1.00x
1.25rem : 2.00x
clamp : 1.72x
Birinci tablonun ilk sütunu sonucun tamamını taşıyor: yalnız görüntü alanı birimiyle yazılan yazı boyutu yakınlaştırmadan hiç etkilenmiyor. Nedeni aritmetiktir. Yakınlaştırma oranı iki katına çıktığında görüntü alanı CSS pikseli cinsinden yarıya iner; yazı boyutu da yarıya iner; her CSS pikseli iki aygıt pikseli olduğu için sonuç değişmez. Kullanıcı yakınlaştırma yapar, sayfadaki her şey büyür, yazı olduğu yerde kalır.
Taban birimle yazılan boyut iki katına çıkar. Karışık ifade ikisinin arasındadır: 1,72 katı. Ölçek oranı, sabit terimin toplam içindeki payı kadardır; görüntü alanı birimi ağırlaştıkça tepki azalır.
İkinci tablo aynı sayıları veriyor. Bu bir rastlantı değil: sabit terim taban birimle, değişken terim görüntü alanı birimiyle yazıldığında, yakınlaştırmayı iki katına çıkarmak ile kök yazı boyutunu iki katına çıkarmak aynı sonucu üretir. İki ayar da aynı ifadeden geçer.
Erişilebilirlik ölçütü buradan okunur. WCAG 1.4.4 ölçütü, metnin yardımcı bir araç gerektirmeden yüzde 200’e kadar büyütülebilmesini ve bunun içerik ya da işlev kaybına yol açmamasını ister. Yalnız görüntü alanı birimiyle yazılan bir yazı boyutu bu ölçütü karşılamaz. Kural yalındır: tercih edilen değerin taban birimle yazılmış bir bileşeni olmalıdır; görüntü alanı birimi tek başına kullanılmaz.
Yazının Diğer Ölçüleri
Yazı boyutu tek değişken değildir.
Satır aralığı birimsiz yazılır: line-height: 1.5 bir orandır ve her ögede kendi yazı
boyutuyla çarpılır. Uzunluk yazıldığında — line-height: 24px — kalıtımla geçen şey hesaplanmış
uzunluktur; 32 birimlik bir başlık, 24 birimlik satır aralığıyla kalır ve satırlar üst üste
biner. Oran ayrıca ölçekle de değişir: küçük yazıda daha geniş, büyük başlıkta daha dar satır
aralığı okunurluğu artırır.
Harf aralığı büyük boyutlarda daralır. Başlık boyutu büyüdükçe harfler arasındaki boşluk görsel olarak açılır; hafif bir eksi değer bunu dengeler. Gövde yazısında böyle bir düzeltme gerekmez.
Satır kırma davranışı iki bildirimle ayarlanır. text-wrap: balance başlıklarda satırların
uzunluğunu eşitler ve son satırda tek kelime kalmasını önler; text-wrap: pretty uzun metinlerde
paragraf sonundaki tek kelimeyi düzeltir. İkisi de öneridir, garanti değil.
Heceleme, hyphens: auto ile açılır ve yalnız belgenin dili bildirilmişse çalışır — Web’in
Temelleri ve HTML kursunda kurulan dil bildirimi burada işlevsel bir karşılık kazanır. Dar
sütunlarda satır sonlarındaki büyük boşlukları azaltır.
/* duzen.css — 10. adım: akışkan tipografi ölçeği */ :root { --yazi-govde: clamp(1rem, 0.9022rem + 0.4348vw, 1.25rem); --yazi-baslik: clamp(1.5rem, 1.1087rem + 1.7391vw, 2.5rem); } body { font-size: var(--yazi-govde); line-height: 1.6; } h1 { font-size: var(--yazi-baslik); line-height: 1.15; letter-spacing: -0.01em; text-wrap: balance; } .istasyon-notlari { max-inline-size: 675px; hyphens: auto; text-wrap: pretty; }
İki özel özellik, iki türetilmiş ifade taşıyor. Satır aralığı gövdede 1,6, başlıkta 1,15; birimsiz oldukları için ikisi de kendi yazı boyutuyla çarpılıyor. Sütunun üst sınırı taban birimle değil piksel cinsinden yazılmış durumda — bu bilinçli bir seçimdir: sütun genişliği satır uzunluğu denetiminden geliyor ve o denetim yazı boyutunu zaten hesaba katıyor.
Özet
- Akışkan yazı boyutu iki ölçü noktasından türetilir; eğim görüntü alanı birimiyle, sabit terim
taban birimle yazılır ve
clamp()ifadesinin orta terimini oluşturur. - Ölçek adımları farklı eğimlerle yazıldığında başlık–gövde oranı dar düzende daralır, geniş düzende açılır; bu istenen davranıştır.
- Satır uzunluğu, sütun genişliğinin yazı boyutuna oranıdır ve 45–75 karakter aralığında tutulur; çok dar düzenlerde alt sınır karşılanamaz ve bu kısıt bilinerek kabul edilir.
- Yalnız görüntü alanı birimiyle yazılan yazı boyutu yakınlaştırmadan etkilenmez ve metnin yüzde 200’e kadar büyütülebilmesini isteyen ölçütü karşılamaz.
- Yakınlaştırmayı iki katına çıkarmak ile kök yazı boyutunu iki katına çıkarmak aynı ifadeden geçer ve aynı sonucu verir.
- Satır aralığı birimsiz yazılır; uzunluk yazıldığında kalıtımla geçen hesaplanmış değer büyük yazılarda satırların üst üste binmesine yol açar.
Sonraki Adım
Yazı ölçekle birlikte değişiyor, düzen kabına göre uyarlanıyor. Geriye sayfanın en ağır ögesi kalıyor: görsel. Bir görsel, dar bir ekranda gereğinden büyük bir dosyayla indirilebilir ya da geniş bir ekranda bulanık görünebilir; ikisi de aynı bildirimden doğar. Üstelik bazı görsellerde sorun ölçü değil içeriktir — geniş bir manzara karesinin dar ekranda anlamlı kalması için kırpılması gerekir. Sonraki ders bu iki soruyu ayırır: tarayıcı hangi dosyayı seçer ve seçimi kim yönlendirir?
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.