İçeriğe geç
academia.sh

Ders 03 / 27

Görsel ve Yazı Tipi Optimizasyonu

Görselin aktarım, çözme ve çizim maliyetlerinin ayrılması; aday kümesinden doğru dosyanın seçilmesinin hesabı, biçim sınıflarına göre karar ve yazı tipi yükleme stratejisinin zaman çizelgesi.

İçindekiler

Kritik yol kısaldığında ilk boyama erkene çeker. En büyük içerik boyası ise çoğu sayfada bir metin bloğu değil, bir görseldir: istasyon listesindeki kart görselleri ve ölçüm ayrıntısı sayfasındaki istasyon fotoğrafı, belgenin kendisinden çok daha fazla bayt taşır. Yazı tipi dosyaları ise metnin ne zaman okunabilir hâle geleceğini belirler.

Bu ders iki varlık türünün boyut, biçim ve yükleme kararlarını ele alır.

Bir Görselin Üç Ayrı Maliyeti

Görsel eniyilemesi çoğunlukla tek bir sayıya indirgenir: dosya boyutu. Oysa aynı görsel üç ayrı yerde maliyet üretir ve bunlar birbirinden bağımsızdır.

Aktarım maliyeti indirilen bayt sayısıdır. Sıkıştırma bunu düşürür.

Çözme maliyeti sıkıştırılmış baytların piksellere çevrilmesidir. İşlemci zamanı harcar ve sonucunda bellekte, sıkıştırmadan bağımsız bir yer kaplar: piksel başına dört bayt. Ağ Panelinde Tanı dersindeki aktarılan boyut–kaynak boyutu ayrımının görsellerdeki karşılığı budur ve burada fark çok daha büyüktür. İyi sıkışan bir fotoğraf ağı yormaz, belleği yorar.

Çizim maliyeti çözülmüş pikselin ekrandaki kutuya ölçeklenmesidir. Kaynak piksel sayısı hedef kutudan büyükse fazlalık her karede yeniden ölçeklenir.

İkinci ve üçüncü maliyet, seçilen dosyanın piksel boyutuna bağlıdır; dosya boyutuna değil. Aşağıdaki hesap bu ayrımı sayılara döker.

// aday.mjs — aday kumesinden hangi dosyanin secildigi ve cozulmus piksel maliyeti

// istasyon karti gorseli: en boy orani 3:2
const adaylar = [400, 800, 1200, 1600, 2400]; // genislik tanimlayicilari (w)
const EN_BOY = 2 / 3;

// sizes bildirimi: 720 pikselden dar gorunum alaninda tam genislik, uzerinde 360 piksel
const yerlesimGenisligi = (gorunumGenisligi) =>
  gorunumGenisligi <= 720 ? gorunumGenisligi - 32 : 360;

function secilenAday(gorunumGenisligi, pikselOrani) {
  const gereken = yerlesimGenisligi(gorunumGenisligi) * pikselOrani;
  return adaylar.find((a) => a >= gereken) ?? adaylar[adaylar.length - 1];
}

const cozulmusBayt = (genislik) => Math.round(genislik * genislik * EN_BOY * 4);

console.log("gorunum".padStart(8) + "oran".padStart(6) + "yerlesim".padStart(10) +
  "gereken".padStart(9) + "secilen".padStart(9) + "cozulmus".padStart(11) +
  "en buyuk aday".padStart(15) + "kat".padStart(7));
for (const [gorunum, oran] of [[390, 2], [390, 3], [768, 1], [768, 2], [1280, 2]]) {
  const secilen = secilenAday(gorunum, oran);
  const gereken = yerlesimGenisligi(gorunum) * oran;
  const secilenBayt = cozulmusBayt(secilen);
  const enBuyukBayt = cozulmusBayt(adaylar[adaylar.length - 1]);
  console.log(
    `${gorunum}px`.padStart(8) + `${oran}x`.padStart(6) +
    `${yerlesimGenisligi(gorunum)}px`.padStart(10) + `${gereken}px`.padStart(9) +
    `${secilen}w`.padStart(9) +
    `${(secilenBayt / 1024 / 1024).toFixed(2)} MB`.padStart(11) +
    `${(enBuyukBayt / 1024 / 1024).toFixed(2)} MB`.padStart(15) +
    `${(enBuyukBayt / secilenBayt).toFixed(1)}x`.padStart(7));
}
console.log("cozulmus = genislik x yukseklik x 4 bayt (kanal basina 1 bayt, RGBA)");
console.log("kat = en buyuk aday secilseydi cozulmus bellegin kac kati olacagi");
 gorunum  oran  yerlesim  gereken  secilen   cozulmus  en buyuk aday    kat
   390px    2x     358px    716px     800w    1.63 MB       14.65 MB   9.0x
   390px    3x     358px   1074px    1200w    3.66 MB       14.65 MB   4.0x
   768px    1x     360px    360px     400w    0.41 MB       14.65 MB  36.0x
   768px    2x     360px    720px     800w    1.63 MB       14.65 MB   9.0x
  1280px    2x     360px    720px     800w    1.63 MB       14.65 MB   9.0x
cozulmus = genislik x yukseklik x 4 bayt (kanal basina 1 bayt, RGBA)
kat = en buyuk aday secilseydi cozulmus bellegin kac kati olacagi

Seçim iki adımda yapılır. Önce sizes bildiriminden ögenin yerleşim genişliği çözülür; bu, ortam sorgularıyla yazılmış bir kural kümesidir ve tarayıcı görüntü alanına bakarak tek bir CSS piksel değeri üretir. Sonra bu değer piksel oranıyla çarpılır ve aday kümesinden bu sayıya yeten en küçük dosya seçilir.

Tablonun anlattığı asıl şey son sütundur. Aynı görselin en büyük adayı her koşulda çözüldüğünde on dört buçuk megabaytlık piksel verisi üretir; oysa dar bir ekranda dört yüz piksellik dosya yeterlidir ve otuz altı kat daha az bellek harcar. Bu fark dosya boyutlarında görünmez — iki dosyanın sıkıştırılmış hâlleri arasındaki oran çok daha küçüktür.

Aynı tabloda ikinci bir gözlem var: geniş ekranda kart daha küçüktür. Duyarlı düzende sütun sayısı arttıkça tek bir kartın genişliği düşer, dolayısıyla masaüstü daima daha büyük görsel ister varsayımı yanlıştır. sizes bildirimi düzenden türetilmelidir, tahminden değil.

Biçim Seçimi

Biçim kararı ürün adlarıyla değil, içerik sınıflarıyla verilir.

Vektör mü, ızgara mı? Simgeler, çizelgeler, logolar ve çizgi grafikleri geometriyle tanımlıdır; vektör biçiminde saklandıklarında her ölçekte keskin kalır ve çözülmüş bellekleri piksel sayısına değil geometri karmaşıklığına bağlıdır. Fotoğraf ızgara biçimindedir; vektöre çevrilemez.

Kayıplı mı, kayıpsız mı? Kayıplı kodlayıcı, gözün ayırt etmediği bilgiyi atarak sıkıştırır ve fotoğraf için doğru seçimdir. Kayıpsız kodlayıcı her pikseli korur; keskin kenarların bulunduğu içerikte — ekran görüntüsü, metin içeren görsel, düz renk alanları — kayıplı sıkıştırmanın bıraktığı bulanıklık görünür hâle gelir.

Saydamlık gerekiyor mu? Alfa kanalı destekleyen bir biçim seçilmelidir; gerekmiyorsa seçilmemelidir, çünkü dördüncü kanal veri ekler.

Aşamalı çözünürlük veriliyor mu? Bazı biçimler dosyanın ilk baytlarından düşük çözünürlüklü bir sürüm üretilmesine izin verir. Büyük bir görselde bu, kullanıcının bir şey görmesiyle her şeyi görmesi arasındaki süreyi ayırır.

Farklı biçimlerin farklı istemcilerde desteklenmesi picture ögesiyle çözülür: kaynak listesindeki her seçenek kendi içerik türünü bildirir, istemci tanımadığı türü atlar ve sonunda img ögesindeki karşılığa düşer. Bu, yetenek saptamanın işaretleme düzeyindeki karşılığıdır; hangi biçimin destekleneceğine dair varsayım gerektirmez.

Ne Zaman İstenir

Doğru dosya seçildikten sonra iki karar kalır: ne zaman istenecek ve yeri baştan ayrılacak mı?

Gecikmeli yükleme görünüm alanının dışındaki görsellerin istenmesini erteler. Kuralın tek istisnası önemlidir: en büyük içerik boyasına aday olan görsel gecikmeli yüklenmemelidir. Ertelenen istek, ölçütün kendisini geciktirir.

Öncelik bildirimi aynı sorunun diğer ucudur. Belgede geçen bütün görseller öntanımlı olarak düşük öncelikle istenir; ilk ekrandaki kahraman görsel için fetchpriority="high" yazıldığında istek diğerlerinin önüne geçer.

Yer ayırma başarım değil kararlılık kararıdır, ama aynı ögede verilir. Görsele width ve height öznitelikleri yazıldığında tarayıcı en boy oranını dosya inmeden bilir ve kutuyu baştan ayırır. Yazılmadığında, görsel indiği anda altındaki her şey kayar — ilk derste hesaplanan puanın en yaygın kaynağı budur.

Yazı Tipinin Zaman Çizelgesi

CSS ile Görsel Sunum kursundaki Yazı Tipi Yükleme dersi font-display değerlerini iki döneme göre ayırmıştı: engelleme süresi boyunca metin çizilmez, değiştirme süresi boyunca yedek yazı tipiyle çizilir. Burada sorulan soru farklıdır: dosya belirli bir anda gelirse kullanıcı ne görür?

// yazitipi-cizelge.mjs — dosya varis anina gore metnin durumu
// Belirtimde tanimli uc donem: engelleme, degistirme, geri cekilme.
const DONEMLER = {
  block:    { engelleme: 3000, degistirme: Infinity },
  swap:     { engelleme: 100,  degistirme: Infinity },
  fallback: { engelleme: 100,  degistirme: 3000 },
  optional: { engelleme: 100,  degistirme: 0 },
};

function cizelge(deger, varisAni) {
  const { engelleme, degistirme } = DONEMLER[deger];
  const gorunmezSure = Math.min(varisAni, engelleme);
  if (varisAni <= engelleme) {
    return { gorunmezSure, yedekSure: 0, sonuc: "istenen yazi tipi" };
  }
  const degistirmeSonu = engelleme + degistirme;
  if (varisAni <= degistirmeSonu) {
    return { gorunmezSure, yedekSure: varisAni - engelleme, sonuc: "istenen yazi tipi" };
  }
  return { gorunmezSure, yedekSure: Infinity, sonuc: "yedek yazi tipi kalir" };
}

const sure = (ms) => (ms === Infinity ? "sayfa boyunca" : `${ms} ms`);

console.log("--- dosya varis anina gore metnin durumu ---");
console.log("deger".padEnd(10) + "varis".padStart(8) + "gorunmez".padStart(10) +
  "yedekle".padStart(15) + "   son durum");
for (const deger of Object.keys(DONEMLER)) {
  for (const varis of [80, 900, 4200]) {
    const c = cizelge(deger, varis);
    console.log(
      deger.padEnd(10) + `${varis} ms`.padStart(8) +
      `${c.gorunmezSure} ms`.padStart(10) + sure(c.yedekSure).padStart(15) +
      "   " + c.sonuc);
  }
}
--- dosya varis anina gore metnin durumu ---
deger        varis  gorunmez        yedekle   son durum
block        80 ms     80 ms           0 ms   istenen yazi tipi
block       900 ms    900 ms           0 ms   istenen yazi tipi
block      4200 ms   3000 ms        1200 ms   istenen yazi tipi
swap         80 ms     80 ms           0 ms   istenen yazi tipi
swap        900 ms    100 ms         800 ms   istenen yazi tipi
swap       4200 ms    100 ms        4100 ms   istenen yazi tipi
fallback     80 ms     80 ms           0 ms   istenen yazi tipi
fallback    900 ms    100 ms         800 ms   istenen yazi tipi
fallback   4200 ms    100 ms  sayfa boyunca   yedek yazi tipi kalir
optional     80 ms     80 ms           0 ms   istenen yazi tipi
optional    900 ms    100 ms  sayfa boyunca   yedek yazi tipi kalir
optional   4200 ms    100 ms  sayfa boyunca   yedek yazi tipi kalir

Dosya hızlı geldiğinde beş değer de aynı sonucu verir; ayrım yavaş koşulda ortaya çıkar. Dokuz yüz milisaniyede gelen bir dosya için block metni dokuz yüz milisaniye boyunca görünmez bırakır, swap ve fallback yüz milisaniye sonra yedek yazı tipiyle çizer, optional ise dosyayı o sayfada hiç kullanmaz.

Karar, hangi ölçütün korunduğuna göre verilir. swap ilk içerik boyasını korur ve düzen kaymasını göze alır: yedek yazı tipiyle çizilen metin, asıl yazı tipi geldiğinde ölçü değiştirir. optional düzen kararlılığını korur ve tasarlanan yazı tipinden vazgeçer. block her ikisini de bozar ve yalnızca yedeği anlamsız olan durumlarda — simge yazı tipleri gibi — savunulabilir.

Süre değerleri belirtimde öneri olarak verilir ve gerçekleştirime göre değişir; modeldeki sayılar bu önerilerden alınmıştır. Değişen sayı, değerlerin birbirine göre sıralamasını değiştirmez.

Yazı tipi maliyetini azaltmanın üç yolu vardır ve üçü de bu tabloyu iyileştirir: dosyayı kendi metnine göre alt kümelere ayırmak indirilecek baytı azaltır, dosyayı preload ile erken istemek varış anını öne çeker, yedek yazı tipini size-adjust ve benzeri tanımlarla asıl yazı tipine ölçüce yaklaştırmak ise değişim anındaki kaymayı sıfıra yaklaştırır.

İstasyon Kartının İşaretlemesi

<article class="istasyon-karti">
  <img
    src="/gorsel/kuzey-yamac-800.img"
    srcset="/gorsel/kuzey-yamac-400.img   400w,
            /gorsel/kuzey-yamac-800.img   800w,
            /gorsel/kuzey-yamac-1200.img 1200w"
    sizes="(max-width: 720px) calc(100vw - 32px), 360px"
    width="1200" height="800"
    fetchpriority="high"
    alt="Kuzey Yamaç istasyonunun kar örtüsü altındaki ölçüm direği">
  <h2>Kuzey Yamaç 1</h2>
</article>

Dosya uzantısı örnekte yer tutucudur; seçilen biçime göre yazılır. Kural uzantıda değil yapıdadır: aday kümesi gerçek piksel genişlikleriyle bildirilir, sizes bildirimi düzenden türetilir, width ve height en boy oranını baştan verir ve öncelik bildirimi yalnızca ilk ekrandaki karta yazılır. Birden çok biçim sunulacaksa aynı img ögesi bir picture içine alınır ve her source kendi içerik türünü bildirir; img son çare olarak kalır.

Listenin görünüm alanı dışında kalan kartlarında öncelik bildirimi bulunmaz; onlara loading="lazy" yazılır. Aynı bileşenin iki farklı örneği farklı bildirimler alır ve bu ayrım bileşen arayüzünde bir seçenek olarak dışarı çıkarılır.

Özet

  • Bir görselin aktarım, çözme ve çizim maliyetleri ayrıdır; çözülmüş bellek dosya boyutuna değil piksel sayısına bağlıdır ve aradaki fark kat kat olabilir.
  • Aday seçimi iki adımdır: sizes bildiriminden yerleşim genişliği çözülür, piksel oranıyla çarpılır ve yeten en küçük aday seçilir; bildirim düzenden türetilmelidir.
  • Biçim kararı ürün adıyla değil içerik sınıfıyla verilir: vektör mü ızgara mı, kayıplı mı kayıpsız mı, saydamlık gerekli mi, aşamalı çözünürlük veriliyor mu.
  • En büyük içerik boyasına aday olan görsel gecikmeli yüklenmez; öncelik bildirimi yalnızca ilk ekrandaki görsele yazılır ve yer ayırma her görselde yapılır.
  • Yazı tipi görüntüleme davranışı bir ölçüt tercihidir: swap ilk içerik boyasını, optional düzen kararlılığını korur.

Sonraki Adım

Buraya kadarki kararların hepsi belgenin ve varlıkların kendisiyle ilgiliydi: hangi dosya, ne kadar büyük, ne zaman istenir. Bir katman daha var ve orada tek bir bayt bile azaltmadan kazanç elde edilebilir. Aynı kullanıcı istasyon listesini ikinci kez açtığında aynı dosyaları yeniden indirmek zorunda mıdır? Bağlantı kurulumu her seferinde baştan mı yapılır? Bu soruların yanıtı istekte değil, yanıtın taşıdığı başlıklarda ve belgeye yazılan bağlantı ipuçlarındadır. Sonraki ders bu başlıkları yerel bir sunucu üzerinde ölçerek ele alır.

İ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