Modern siteler custom web font kullanıyor. Google Fonts, Adobe Fonts, self-hosted font dosyaları. Ama font loading’in yanlış yapılması LCP’yi vuruyor, kullanıcı deneyimini bozuyor.
3 projede font optimization yaptım. Her birinde FOUT/FOIT trade-off’u farklı karar gerektirdi.
FOUT ve FOIT nedir
FOUT (Flash of Unstyled Text): custom font yüklenirken browser fallback font’u gösteriyor, font yüklendiğinde değişiyor. Kullanıcı “şey, font değişti” diye tökezliyor ama en azından metni okuyabiliyor.
FOIT (Flash of Invisible Text): custom font yüklenene kadar metin invisible. Blank space. Kullanıcı “metin neden yok?” diye düşünüyor. Font gelince hepsi birden ortaya çıkıyor.
Hangi kötü? İkisi de kötü ama FOIT daha kötü çünkü metin görünmüyor, content blocking var.
font-display: CSS’in cevabı
font-display property font-face declaration’ında tercihi kontrol ediyor:
@font-face{
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap;
}Değerler:
- auto: browser karar verir (genelde FOIT)
- block: kısa süre invisible, sonra fallback. Sonra custom yüklenince swap
- swap: fallback hemen göster, font gelince swap. Tipik FOUT
- fallback: çok kısa block, sonra fallback, font çok geç gelirse fallback’te kal
- optional: block, sonra fallback. Custom font cache’e gelir future request için hazır ama bu request’te kullanılmaz
Hangi değeri seçmeli?
Ben çoğunlukla swap tercih ediyorum. İstisnalar:
Brand-critical logo fonts: block OK. Logo custom font olmadan kötü görünüyor, kısa süre blank daha iyi.
Long-form content (blog, article): swap net. Metin kesinlikle görünmeli.
Navigation, UI: swap veya optional. Fallback font’u yakın (same metrics) ise FOUT bile minimal.
Brand fonts with no fallback match: fallback düşün. Custom font çok geç gelirse fallback’te kalsın, daha az layout shift.
Font loading stratejisi
font-display tek başına yetmez. Font’u ne kadar hızlı yüklediğiniz de kritik.
1. WOFF2 kullan. Modern format. WOFF’a göre %30 daha küçük. WOFF2 desteklenmeyen browser yok sayılır.
2. Subset yap. Türkçe site’te Arabic glyph’leri lazım değil. Google Fonts latin subset default, latin-ext Türkçe için ek. Self-hosted’da pyftsubset veya online tool ile subset üret.
3. Preload critical fonts. içinde:
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>Browser ne erken font istediğinizi öğreniyor, CSS parse’ı beklemeden fetch başlatıyor. FOIT/FOUT süresi kısalıyor.
4. Self-host yerine Google Fonts?
Eskiden CDN nedeni ile Google Fonts daha hızlıydı. Şimdi Chrome font cache’i ayrı tutmuyor, self-hosted eşit veya daha hızlı.
Self-host avantajları:
– Same origin (no DNS lookup)
– Tam kontrol (subset, format)
– GDPR (Google’ın eline IP gitmiyor)
Google Fonts avantajları:
– Setup kolay
– Font repository gelişmiş
– Multiple version management
GDPR önemli ise self-host. Çoğu case’te self-host öneriyorum.
Variable fonts
Variable font: tek dosyada farklı weight/style combo’ları. Inter ailenin ayrı ayrı light/regular/bold dosyaları yerine tek Inter-Variable.woff2.
Avantaj:
– Tek HTTP request
– Toplam boyut multiple file’dan küçük
– Intermediate weight’ler erişilebilir (375 weight gibi)
font-variation-settings ile weight kontrol:
.heading {
font-family: 'Inter';
font-weight: 650; /* variable weight */
}Modern browser’lar hepsi destekliyor. Inter, Roboto Flex, Source Sans 3 gibi popüler font’ların variable version’ı var.
Fallback stack design
swap kullanıyorsanız fallback önemli:
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}Fallback metric-wise custom font’a yakın olmalı, yoksa swap olduğunda layout shift büyük. Bu CLS’i bozuyor.
size-adjust: advanced technique
CSS Font Module Level 4’teki size-adjust, ascent-override, descent-override, line-gap-override fallback font’u custom font’un boyutlarına uydurmak için.
@font-face{ font-display:swap;
font-family: 'FallbackInter';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
}
body {
font-family: 'Inter', 'FallbackInter', sans-serif;
}Browser Arial kullanıyor ama Inter’e uyuyor metrics-wise. Swap olduğunda layout shift minimal.
Bu technique CLS’i neredeyse 0’a indiriyor. fontpie gibi tool’lar otomatik calculate ediyor.
Ölçüm: nasıl etkiyi görüyoruz
- FCP: font block olmuyorsa hızlı
- LCP: hero’daki metin custom font bekliyorsa LCP gecikir
- CLS: swap yaparken shift görünüyor mu?
- Chrome DevTools Performance panel: font request timing
Lighthouse raporunda “Ensure text remains visible during webfont load” uyarısı ise font-display: swap eksik demektir.
Ikon font vs SVG
Font Awesome gibi ikon font’lar eski yöntem. 2026’da SVG ikon önerisi daha güçlü:
- Icon font: tüm ikon set yükleniyor (500+ KB), tek ikon render için
- SVG inline: sadece kullandığın ikon
- SVG sprite: hepsi ayrı dosyada, cacheleniyor
Icon font’u bırakın, SVG’ye geçin.
Bir e-ticaret örneği
Müşteri ürün detay sayfasında custom display font kullanıyordu, hero’da büyük başlık. FOIT yaşanıyordu, LCP 3.2 saniye.
Optimization:
– font-display: swap eklendi
– WOFF2 variable version’a geçildi (800 KB → 210 KB)
– critical font için
– Fallback font metric-wise ayarlandı (size-adjust)
Result:
– LCP 3.2s → 1.6s
– CLS minimal (size-adjust ile shift görünmez hale geldi)
– Visual polish korundu
Yaygın hatalar
1. Çok fazla font family. 3+ family = 6+ file request. 1-2 family yeterli.
2. 5+ weight yüklemek. regular + bold yeterli çoğunlukla. Light, medium, semibold, black nadiren gerekli.
3. Italic variant’ı otomatik yüklemek. Italic kullanmıyorsan yükleme.
4. Third-party font script. Adobe Fonts JS loader ve benzer tool’lar extra JS çalıştırıyor. Self-host daha temiz.
5. @import içinde font. CSS file yüklenmeden font yüklenmiyor. şart.
Son tavsiye
Font optimization quick win. 1-2 saatlik iş, LCP’yi saniyeler iyileştirebiliyor. Yaklaşım:
- WOFF2 variable font tercih et
- font-display: swap
- Preload critical fonts
- Fallback stack metric-similar
- Subset Turkish için latin-ext
- 2-3 weight yeter
Bu 6 adım %80 fayda sağlıyor. Arada geçecek 2-3 saat yıllara yayılacak LCP iyileşmesine dönüşüyor.