Google Fonts ve Türkçe: latin-ext Neden 85 KB?
Türkçe bir sitede Google Fonts'u açınca ağda iki font dosyası görürsün: latin ve latin-ext. Inter için ikincisi 85 KB, içinden de yalnızca altı karakter lazım.
Google Fonts Fontu Parçalara Böler
Google, her fontu script'lere göre ayrı dosyalara bölüyor: latin, latin-ext, cyrillic, greek, vietnamese. Her parçanın @font-face kuralında bir unicode-range var ve tarayıcı yalnızca sayfada kullanılan karakterlerin parçasını indiriyor.
Türkçe bu bölünmeye tam oturmuyor:
| Parça | Boyut | Türkçe için gereken |
|---|---|---|
latin | 48 KB | ASCII harfler, ç, ö, ü, ı |
latin-ext | 85 KB | Ğ, ğ, İ, Ş, ş, ₺ |
Boyutlar Inter variable fontun (v20) woff2 dosyalarından. Türkçe metinde ğ ya da ş neredeyse her sayfada geçtiği için latin-ext de neredeyse her sayfada iniyor. Yani unicode-range burada dosya atlatmıyor ve 85 KB'ın neredeyse tamamı Türkçe'de hiç kullanılmayan karakterler için iniyor.
Next.js: next/font/google
next/font, Google'ın CSS'ini ve font dosyalarını build sırasında indirip kendi sunucundan sunuyor. Tarayıcı Google'a hiç istek atmıyor.
import { Inter } from "next/font/google"
const inter = Inter({
subsets: ["latin", "latin-ext"],
display: "swap"
})
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="tr" className={inter.className}>
<body>{children}</body>
</html>
)
}subsets seçeneği çoğu kişinin sandığı şeyi yapmıyor. Next.js'in kaynak kodunda bu liste yalnızca hangi dosyaların preload edileceğini belirliyor. Google'ın verdiği tüm parçalar CSS'e yine giriyor. Yani subsets: ["latin"] yazsan da ğ ve ş doğru çıkar, latin-ext sadece preload edilmez.
Seçim şu:
["latin"]:latin-extCSS okunduktan sonra, geç iner. O ana kadar ğ ve ş içeren kelimelerin bu harfleri fallback fontla çizilir.["latin", "latin-ext"]: İki dosya da HTML'le birlikte başlar. Preloadunicode-range'e bakmadığı için ikisi de her sayfada iner.
Türkçe sitede latin-ext zaten her sayfada lazım olduğu için ikinci seçenek mantıklı.
Birkaç ayar daha:
displayvarsayılanı zatenswap.adjustFontFallbackvarsayılan olaraktrue. Next, fontun yerine geçen fallback'i metrikleriyle eşleştirip layout shift'i azaltıyor, ellesize-adjustyazmana gerek yok.- Variable fontlarda (Inter gibi)
weightvermen gerekmiyor. Variable olmayanlarda zorunlu.
Tailwind kullanıyorsan variable seçeneğiyle CSS değişkeni tanımlayabilirsin:
const inter = Inter({
subsets: ["latin", "latin-ext"],
variable: "--font-inter"
})
// <html lang="tr" className={inter.variable}>@theme inline {
--font-sans: var(--font-inter);
}85 KB'ı Küçültmek
latin-ext dosyasının içinde yüzlerce karakter var, Türkçe için gereken ise yalnızca altısı. Her karakterin bir Unicode kodu var ve unicode-range ile subset bu kodlarla tanımlanıyor:
| Kod | Harf |
|---|---|
U+011E, U+011F | Ğ, ğ |
U+0130 | İ |
U+015E, U+015F | Ş, ş |
U+20BA | ₺ (Türk lirası) |
Dosyayı bu karakterlere indirmek için fonttools kütüphanesinin pyftsubset komutu yeterli. Python'un paket yöneticisi pip ile kurulur: fonttools komutun kendisini, brotli ise woff2 çıktısı için gereken sıkıştırmayı sağlıyor. latin-ext dosyasının adresini Google'ın CSS çıktısında /* latin-ext */ yorumunun altında bulabilirsin. Inter'de 3.276 byte'lık bir dosya çıktı:
pip install fonttools brotli
pyftsubset inter-latin-ext.woff2 \
--unicodes="U+011E-011F,U+0130,U+015E-015F,U+20BA" \
--flavor=woff2 \
--output-file=inter-turkish-wght-normal.woff2Variable fontta wght ekseni korunuyor. Sonra bu dosyayı kendi @font-face kuralınla, aynı unicode-range ile bağlıyorsun:
@font-face {
font-family: "Inter Variable";
font-display: swap;
font-weight: 100 900;
src: url("/fonts/inter-turkish-wght-normal.woff2") format("woff2-variations");
unicode-range: U+011E-011F, U+0130, U+015E-015F, U+20BA;
}Bunun için fontu kendin barındırman gerekiyor; next/font/google özel subset kabul etmiyor. Bedeli de var: metinde "Łukasz" gibi bir isim geçerse ł harfi hiçbir parçada olmadığı için fallback fontla çıkar.
Sabit bir metin için (logo, başlık) daha basit bir yol var: Google'ın &text= parametresi yalnızca verdiğin harfleri içeren tek bir dosya döndürüyor. text=ğĞşŞİ ile Inter için 4 KB'lık bir dosya geldi. Değişen içerikte bu yol işe yaramaz.
Özet
Türkçe harfler için 85 KB'lık latin-ext dosyasının tamamını indirmen gerekmiyor. Altı karakterlik bir subset aynı işi yaklaşık 3 KB ile görüyor. Özel subset istemiyorsan, Next.js'te latin-ext'i subsets listesine eklemek ve preload'u bilinçli seçmek yeterli.