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:
sizesbildiriminden 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:
swapilk içerik boyasını,optionaldü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.