İçeriğe geç
Performance

Web Font Loading Stratejileri: FOUT, FOIT ve Çözümleri

Tarık Tunç
Web Font Loading Stratejileri: FOUT, FOIT ve Çözümleri

Web Font Loading Stratejileri: FOUT, FOIT ve Çözümleri

Web fontları, markaların dijital kimliğinin önemli bir parçasıdır. Ancak özel font dosyaları, sayfa yükleme süresini artırabilir ve kullanıcı deneyimini olumsuz etkileyebilir. Ortalama bir web fontları paketi 100-300KB arasında boyuta sahiptir ve yanlış yükleme stratejisi FOUT (Flash of Unstyled Text) veya FOIT (Flash of Invisible Text) sorunlarına yol açar. Bu rehberde web font yükleme stratejilerini, performans optimizasyonlarını ve CLS etkisini minimize etme yöntemlerini detaylı olarak inceleyeceğiz.

FOUT ve FOIT Nedir?

Font yüklenirken tarayıcılar iki farklı davranış sergiler:

  • FOIT (Flash of Invisible Text): Font yüklenene kadar metin görünmez olur. Chrome ve Firefox varsayılan olarak 3 saniye FOIT uygular, ardından fallback fonta geçer.
  • FOUT (Flash of Unstyled Text): Metin önce sistem fontu ile gösterilir, özel font yüklenince değişir. Bu geçiş CLS'ye neden olabilir.
Bilgi: FOIT kullanıcıya boş sayfa deneyimi yaşatırken, FOUT en azından içeriği okumaya başlamasına izin verir. Performans açısından FOUT, FOIT'a tercih edilir. font-display: swap ile FOUT davranışını zorunlu kılabilirsiniz.

font-display Değerleri

CSS font-display özelliği, font yüklenirken tarayıcının davranışını kontrol eder:

@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
  font-weight: 400;

  /* swap: Hemen fallback göster, font yüklenince değiştir */
  /* CLS riski var ama metin hemen görünür */
  font-display: swap;

  /* optional: 100ms bekle, yüklenmediyse bu sayfa için atla */
  /* Sonraki sayfa yüklemelerinde cache'ten kullanılır */
  /* En iyi performans, CLS riski yok */
  font-display: optional;

  /* fallback: 100ms FOIT + 3s swap window */
  /* Orta yol - kısa bekleme süresi */
  font-display: fallback;

  /* block: 3s FOIT (varsayılan davranış) */
  /* Kullanmayın - kötü UX */
  font-display: block;

  /* auto: Tarayıcı karar verir (genellikle block) */
  font-display: auto;
}

/* Google Fonts ile font-display kullanımı */
/* URL'ye &display=swap parametresi ekleyin */
/* https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap */

Font Dosya Formatı ve Subsetting

WOFF2, en verimli web font formatıdır. Brotli sıkıştırma ile WOFF'a göre %30 daha küçük boyut sunar. Font subsetting ile sadece kullanılan karakter aralıklarını dahil ederek dosya boyutunu daha da azaltabilirsiniz:

# pyftsubset ile font subsetting (fonttools paketi)
pip install fonttools brotli

# Sadece Türkçe ve Latin karakterleri dahil et
pyftsubset CustomFont.ttf \
  --output-file=CustomFont-subset.woff2 \
  --flavor=woff2 \
  --layout-features='kern,liga,calt' \
  --unicodes="U+0000-00FF,U+0100-024F,U+0130,U+0131,U+011E,U+011F,U+015E,U+015F"

# Veya glyphhanger ile otomatik analiz
npx glyphhanger https://example.com --subset=CustomFont.ttf --formats=woff2

# unicode-range ile tarayıcıya sadece gerekli alt kümeyi indirmesini söyle
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC;
}

@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom-turkish.woff2') format('woff2');
  unicode-range: U+011E-011F, U+0130-0131, U+015E-015F;
}
İpucu: Google Fonts otomatik olarak unicode-range subsetting uygular. Kendi fontlarınızı kullanıyorsanız, subsetting ile dosya boyutunu %50-80 oranında azaltabilirsiniz. Türkçe site için Latin Extended + Türkçe karakterler yeterlidir.

Preload ile Font Yüklemeyi Hızlandırma

Font dosyaları genellikle CSS parse edildikten sonra keşfedilir. Preload ile bu keşfi öne çekebilirsiniz:

<!-- Critical fontları preload et -->
<link rel="preload"
      href="/fonts/inter-regular.woff2"
      as="font"
      type="font/woff2"
      crossorigin>

<link rel="preload"
      href="/fonts/inter-bold.woff2"
      as="font"
      type="font/woff2"
      crossorigin>

<!-- crossorigin attribute zorunludur, font dosyaları her zaman
     CORS ile yüklenir (aynı origin'den olsa bile) -->
Uyarı: Tüm font ağırlıklarını preload etmeyin. Sadece above-the-fold için kritik olan 1-2 font dosyasını preload edin. Fazla preload, diğer kritik kaynakların (CSS, JS) bant genişliğini çalar ve performansı olumsuz etkiler.

CLS'yi Minimize Etme: Font Metric Override

Font swap sırasında oluşan CLS'yi azaltmak için fallback fontun metriklerini özel fonta yaklaştırabilirsiniz:

/* CSS Font Metric Override ile CLS azaltma */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter.woff2') format('woff2');
  font-display: swap;

  /* Fallback font metriklerini ayarla */
  /* Bu değerler fallback font ile özel font arasındaki farkı azaltır */
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* Fallback font tanımı */
body {
  font-family: 'Inter', 'Inter-fallback', system-ui, sans-serif;
}

/* Next.js otomatik font metric override sağlar */
/* next/font kullanımı */
// Next.js ile otomatik font optimizasyonu
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin', 'latin-ext'],
  display: 'swap',
  // Next.js otomatik olarak:
  // - Self-hosting yapar (Google'a istek yok)
  // - Font metric override uygular (CLS yok)
  // - Preload ekler
  // - Subsetting yapar
});

export default function Layout({ children }) {
  return (
    <html className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

Font Loading API ile Kontrol

JavaScript Font Loading API ile font yüklenme durumunu programatik olarak kontrol edebilirsiniz:

// Font Loading API ile gelişmiş kontrol
async function loadFonts() {
  // Font yüklenmeden önce body'ye class ekle
  document.documentElement.classList.add('fonts-loading');

  try {
    // Kritik fontları yükle
    await Promise.all([
      document.fonts.load('400 1em Inter'),
      document.fonts.load('700 1em Inter')
    ]);

    // Font yüklendiğinde class değiştir
    document.documentElement.classList.remove('fonts-loading');
    document.documentElement.classList.add('fonts-loaded');

    // Session storage'a kaydet - sonraki sayfa yüklemelerinde anında göster
    sessionStorage.setItem('fontsLoaded', 'true');
  } catch (err) {
    console.warn('Font loading failed:', err);
    document.documentElement.classList.remove('fonts-loading');
  }
}

// Daha önce yüklendiyse hemen class ekle
if (sessionStorage.getItem('fontsLoaded')) {
  document.documentElement.classList.add('fonts-loaded');
} else {
  loadFonts();
}

Font Yükleme Stratejisi Seçimi

Senaryo Önerilen Strateji font-display
Blog / İçerik sitesi font-display: optional + preload optional
Marka odaklı site font-display: swap + metric override swap
E-ticaret font-display: fallback + preload fallback
Web uygulaması (SPA) Self-hosted + preload + swap swap

Sonuç

Web font optimizasyonu, hem görsel kalite hem de performans arasında denge kurmayı gerektirir. WOFF2 formatı kullanın, subsetting ile dosya boyutunu minimize edin, preload ile keşfi hızlandırın ve font-display ile yükleme davranışını kontrol edin. Font metric override ile CLS'yi sıfıra yaklaştırarak hem hızlı hem de görsel olarak stabil bir deneyim sunabilirsiniz.

Kaynaklar

İlgili Yazılar