İçeriğe geç
academia.sh

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat