Uvod: Zašto su web fontovi tihi ubojica performansi
Hajde da budemo iskreni — fontovi su nešto o čemu većina developera razmišlja otprilike deset sekundi. Odabereš Google Font, ubaciš link tag i gotovo. Ali evo u čemu je kvaka: fontovi su često treći ili četvrti najveći resurs na stranici, odmah iza slika i JavaScripta. Govorimo o 100 KB do 500 KB samo za fontove, a stranice s više tipografskih stilova lako prelaze i megabajt.
I to nije samo pitanje veličine datoteka.
Fontovi izravno utječu na tri ključne Core Web Vitals metrike: blokiraju prikazivanje teksta (što utječe na LCP), uzrokuju pomake rasporeda prilikom zamjene (što uništava CLS) i usporavaju prvi prikaz sadržaja (FCP). Drugim riječima, loše optimizirani fontovi mogu pokvariti korisničko iskustvo na svim frontovima — a vi možda ni ne znate da je to problem.
U ovom vodiču prolazimo kroz sve moderne tehnike optimizacije web fontova — od WOFF2 formata i varijabilnih fontova, preko strategija učitavanja s font-display, do naprednih CSS deskriptora koji eliminiraju pomake rasporeda. Svaka tehnika dolazi s primjerima koda koje možete odmah copy-pasteati u svoj projekt.
Kako web fontovi utječu na Core Web Vitals
Prije nego što krenemo u optimizaciju, vrijedi razumjeti što se zapravo događa ispod haube. Kad preglednik naiđe na tekst koji koristi prilagođeni font, prolazi kroz četiri koraka:
- Otkriva da treba font iz CSS-a (
@font-facepravilo) - Započinje preuzimanje font datoteke s poslužitelja
- Dok font nije preuzet, mora odlučiti što napraviti s tekstom (prikazati zamjenski font ili sakriti tekst)
- Kad font stigne, zamjenjuje privremeni font prilagođenim
Svaki od ovih koraka ima svoje performansne implikacije — i svaki se može optimizirati.
Utjecaj na LCP (Largest Contentful Paint)
Ako je najveći vidljivi element na stranici tekstualni blok (naslov, paragraf), LCP direktno ovisi o tome koliko brzo se taj tekst prikaže. Bez odgovarajuće strategije učitavanja fontova, tekst može ostati nevidljiv dok se font ne preuzme — fenomen poznat kao FOIT (Flash of Invisible Text).
Da, to doslovno znači da korisnik gleda praznu stranicu dok se font skida s interneta. Nije sjajno iskustvo.
Utjecaj na CLS (Cumulative Layout Shift)
Kad preglednik zamijeni sistemski font prilagođenim, razlika u veličini i razmacima između ta dva fonta uzrokuje pomak cijeloga sadržaja stranice. Ovaj fenomen naziva se FOUT (Flash of Unstyled Text). Iako je FOUT bolji od FOIT-a (jer korisnik barem vidi tekst), pomak rasporeda može ozbiljno povećati CLS ocjenu.
Iz iskustva, CLS problemi uzrokovani fontovima su među najtežima za dijagnosticirati jer se dogode brzo i izgledaju kao da "sve samo malo poskoči".
Utjecaj na FCP (First Contentful Paint)
FCP mjeri kada preglednik prvi put prikaže bilo kakav sadržaj. Ako fontovi blokiraju prikazivanje teksta, FCP se odgađa. Ovo je posebno bolno na mobilnim uređajima sa sporijim mrežama, gdje preuzimanje fonta od 80 KB može potrajati i nekoliko sekundi.
WOFF2: Jedini format koji trebate koristiti
Ovo je jednostavno — WOFF2 koristi Brotli kompresiju i postiže 30% bolju kompresiju od WOFF-a i preko 50% bolju kompresiju od TTF-a. Konkretno: font Montserrat u TTF formatu zauzima 225 KB, u WOFF-u 94 KB, a u WOFF2 formatu samo 83 KB.
Podrška preglednika za WOFF2 je u 2026. godini praktički univerzalna. Nema nikakvog razloga koristiti bilo koji drugi format kao primarni.
/* Pravilna @font-face deklaracija s WOFF2 */
@font-face {
font-family: 'MojFont';
src: url('/fonts/moj-font.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Ako iz nekog razloga trebate podržavati vrlo stare preglednike (i iskreno, u 2026. to je rijetko potrebno), možete dodati WOFF kao fallback:
@font-face {
font-family: 'MojFont';
src: url('/fonts/moj-font.woff2') format('woff2'),
url('/fonts/moj-font.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Varijabilni fontovi: Jedan font umjesto deset
Ako me pitate koji je najvažniji napredak u web tipografiji posljednjih godina, rekao bih — varijabilni fontovi, bez premišljanja. Umjesto učitavanja zasebnih datoteka za svaku debljinu (regular, bold, light, medium), varijabilni font sadrži sve varijacije unutar jedne datoteke.
Brojke govore same za sebe.
Jedna varijabilna font datoteka obično zauzima 100-200 KB, dok bi šest statičkih font datoteka za iste varijacije zauzimalo 400-800 KB. Na jednom projektu (e-commerce stranica) vidjeli smo smanjenje ukupne veličine fontova s 376 KB na 89 KB — što je rezultiralo poboljšanjem LCP metrike za 22%. Značajno, zar ne?
/* Varijabilni font s rasponom debljina */
@font-face {
font-family: 'InterVariable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
/* Korištenje različitih debljina bez dodatnih HTTP zahtjeva */
h1 { font-family: 'InterVariable', sans-serif; font-weight: 700; }
h2 { font-family: 'InterVariable', sans-serif; font-weight: 600; }
p { font-family: 'InterVariable', sans-serif; font-weight: 400; }
/* Precizna kontrola debljine koja nije moguća sa statičkim fontovima */
.subtle-emphasis { font-weight: 450; }
.semi-bold-custom { font-weight: 550; }
Podrška preglednika za varijabilne fontove u 2026. godini iznosi 92 od 100 na ljestvici kompatibilnosti — Chrome, Firefox, Safari i Edge svi ih u potpunosti podržavaju. Dakle, nema izgovora.
GRAD os: Trend 2026. godine
Ovo je nešto što se tek počinje širiti, ali vrijedi znati. Nova GRAD os (Grade) omogućuje povećanje vizualne težine fonta bez promjene širine znakova. Zašto je to bitno? Jer možete pojačati kontrast teksta za korisnike koji to preferiraju, a da pritom ne uzrokujete nikakav pomak rasporeda. U 2026. godini, GRAD os polako postaje standardni zahtjev za kvalitetne UI fontove.
/* Automatsko prilagođavanje za korisnike koji preferiraju veći kontrast */
@media (prefers-contrast: more) {
body {
font-variation-settings: 'GRAD' 150, 'wght' 450;
}
}
Font subsetting: Uklonite ono što ne koristite
Evo nečeg što me uvijek iznova iznenadi — prosječna font datoteka sadrži tisuće glifova. Latinska, ćirilična, grčka, azijska pisma, matematički simboli i hrpa drugih stvari. Ako vaša stranica koristi samo latinicu (ili latinicu s dijakritičkim znakovima za hrvatski), nepotrebno učitavate stotine kilobajta podataka koje nikada nećete koristiti.
Subsetting rješava taj problem tako da iz font datoteke izbaci sve znakove koji vam ne trebaju. U jednom testu, subsetting je smanjio veličinu font datoteke za 79% — s 99 KB na samo 21 KB. To je ogromna razlika za jednu jedinu datoteku.
Subsetting s pyftsubset alatom
# Instalacija fonttools paketa
pip install fonttools brotli
# Subsetting za latinicu s hrvatskim dijakritičkim znakovima
pyftsubset MojFont.ttf \
--output-file=MojFont-latin-ext.woff2 \
--flavor=woff2 \
--layout-features='kern,liga,calt' \
--unicodes="U+0000-00FF,U+0100-017F,U+0180-024F"
# U+0000-00FF: Osnovna latinica
# U+0100-017F: Proširena latinica A (č, ć, š, ž, đ)
# U+0180-024F: Proširena latinica B
Automatski subsetting s unicode-range deskriptorom
CSS unicode-range deskriptor informira preglednik koji znakovi su sadržani u font datoteci. Preglednik će preuzeti font samo ako se ti znakovi pojavljuju na stranici — i to je prilično pametno ponašanje. Posebno korisno za višejezične stranice.
/* Font samo za latinicu s hrvatskim znakovima */
@font-face {
font-family: 'MojFont';
src: url('/fonts/MojFont-latin-ext.woff2') format('woff2');
font-display: swap;
unicode-range: U+0000-00FF, U+0100-017F, U+0180-024F;
}
/* Zasebna datoteka za ćirilicu — preuzima se samo ako je potrebna */
@font-face {
font-family: 'MojFont';
src: url('/fonts/MojFont-cyrillic.woff2') format('woff2');
font-display: swap;
unicode-range: U+0400-04FF;
}
Važno upozorenje: ako koristite preload za fontove, on zaobilazi unicode-range mehanizam. To znači da će se font preuzeti čak i ako nijedan znak iz tog raspona nije prisutan na stranici. Malo kontraintuitivno, ali tako to radi — koristite preload samo za fontove za koje ste 100% sigurni da će biti potrebni.
font-display: Odaberite pravu strategiju učitavanja
Evo jednog od onih CSS svojstava koje izgleda jednostavno, ali može napraviti ogromnu razliku. font-display kontrolira ponašanje preglednika dok se font učitava, i direktno utječe i na LCP i na CLS. Dva glavna kandidata su swap i optional.
font-display: swap
Preglednik odmah prikazuje tekst koristeći sistemski font, a kad se prilagođeni font preuzme, zamjenjuje ga. Dobro za LCP (tekst je odmah vidljiv), ali može uzrokovati CLS zbog razlike u veličini fontova.
/* Preporučeno za naslove i brendirane elemente */
@font-face {
font-family: 'BrandFont';
src: url('/fonts/brand.woff2') format('woff2');
font-display: swap;
}
font-display: optional
Ovo je moj favorit za body tekst. Preglednik koristi prilagođeni font samo ako je već u cache-u ili se preuzme unutar ~100ms. Ako ne stigne na vrijeme, koristi se sistemski font za cijelo trajanje posjeta. Zvuči drastično? Možda. Ali ovo garantira nula pomaka rasporeda, što je za CLS ocjenu neprocjenjivo.
/* Preporučeno za tekst tijela i dugačke paragrafe */
@font-face {
font-family: 'BodyFont';
src: url('/fonts/body.woff2') format('woff2');
font-display: optional;
}
Kombinirana strategija: Najbolje od oba svijeta
U praksi, najbolji pristup je kombinacija — swap za brendirane elemente (logotip, naslove) gdje je vizualni identitet ključan, i optional za tekst tijela gdje je stabilnost rasporeda važnija. Ovo koristimo na većini projekata i rezultati su konzistentno dobri.
/* Brendirani font — swap jer želimo specifičan izgled */
@font-face {
font-family: 'HeadingFont';
src: url('/fonts/heading.woff2') format('woff2');
font-display: swap;
}
/* Tekst tijela — optional jer stabilnost rasporeda ima prioritet */
@font-face {
font-family: 'BodyFont';
src: url('/fonts/body.woff2') format('woff2');
font-display: optional;
}
h1, h2, h3 { font-family: 'HeadingFont', Georgia, serif; }
p, li, td { font-family: 'BodyFont', system-ui, sans-serif; }
Eliminacija CLS-a: CSS deskriptori za usklađivanje fallback fontova
Dakle, koristite font-display: swap i tekst se odmah prikaže — super. Ali onda font stigne i cijela stranica "poskoči". Frustrirajuće. Srećom, moderni CSS nudi četiri deskriptora u @font-face pravilu koji rješavaju upravo ovaj problem:
- size-adjust — globalno skaliranje svih glifova fonta
- ascent-override — visina iznad bazne linije
- descent-override — visina ispod bazne linije
- line-gap-override — razmak između redaka
Ideja je stvoriti prilagođeni fallback font koji ima identične dimenzije kao vaš prilagođeni font, tako da zamjena ne uzrokuje nikakav vidljivi pomak.
/* Prilagođeni web font */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-display: swap;
}
/* Prilagođeni fallback koji oponaša dimenzije Inter fonta */
@font-face {
font-family: 'Inter Fallback';
src: local('Arial');
size-adjust: 107.64%;
ascent-override: 90.49%;
descent-override: 22.56%;
line-gap-override: 0%;
}
/* Korištenje u CSS-u */
body {
font-family: 'Inter', 'Inter Fallback', sans-serif;
}
Ovi deskriptori podržani su u Chrome 87+ i Firefox 89+. Safari podrška još nije potpuna, ali za preko 80% globalnog tržišta ovo funkcionira. Za Safari korisnike, tekst se jednostavno prikaže s normalnim sistemskim fontom — nije idealno, ali nije ni katastrofa.
Automatizacija s alatima
Ručno kalkuliranje ovih vrijednosti je, iskreno, prilično zamorno. Srećom, postoji nekoliko alata koji to automatiziraju:
- Fallback Font Generator — vizualni web alat za podešavanje fallback fontova
- Fontaine — biblioteka koja automatski generira fallback CSS
- Next.js (
@next/font) — automatski koristi metric overrides za fontove - Nuxt.js (
@nuxtjs/fontaine) — automatski generira prilagođene fallback fontove
Osobno, za Next.js projekte koristimo ugrađenu @next/font integraciju jer sve rješava automatski — uključujući subsetting i metric overrides.
Preloading fontova: Ubrzajte otkrivanje
Preglednici normalno otkrivaju potrebu za fontom tek kad parsiraju CSS. To znači da font preuzimanje počinje relativno kasno u procesu učitavanja stranice. preload hint govori pregledniku da počne preuzimanje fonta odmah, bez čekanja na CSS parsing.
<!-- Preload kritičnog fonta u <head> sekciji -->
<link rel="preload"
href="/fonts/Inter-Variable.woff2"
as="font"
type="font/woff2"
crossorigin>
Tri pravila za preload fontova:
- Uvijek dodajte
crossoriginatribut — čak i za self-hosted fontove. Bez njega, preglednik će preuzeti font dvaput. Da, dvaput. To je poznata zamka. - Preloadajte samo kritične fontove — maksimalno 1-2 font datoteke. Ako preloadate sve, zapravo ne preloadate ništa jer preuzimanja međusobno konkuriraju za propusnost.
- Ne koristite preload s
unicode-range— preload zaobilazi unicode-range mehanizam i preuzima font bezuvjetno.
Preconnect za fontove treće strane
Ako (još uvijek) koristite Google Fonts ili drugi CDN za fontove, barem dodajte preconnect hint da se veza s poslužiteljem uspostavi unaprijed:
<!-- Preconnect za Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
Self-hosting vs. CDN: Što je brže u 2026?
Dugo se smatralo da je korištenje Google Fonts CDN-a najbrža opcija. No u 2026. godini, ta priča se promijenila — self-hosting ima nekoliko jasnih prednosti:
- Eliminacija DNS lookup-a i TLS handshake-a za vanjski poslužitelj — ušteda 100-300 ms (a to nije zanemarivo)
- Potpuna kontrola nad cachingom — možete postaviti dugoročne cache headere
- Nema ovisnosti o trećoj strani — ako Google Fonts padne, vaša stranica i dalje radi
- GDPR usklađenost — korisnikova IP adresa se ne dijeli s Googleom (njemački sudovi su još 2022. presudili da korištenje Google Fonts bez pristanka krši GDPR, i ta presuda je postavila presedan)
- HTTP/2 i HTTP/3 multipleksiranje — fontovi se preuzimaju istom vezom kao i ostali resursi
# Preuzimanje Google Fonts za self-hosting pomoću google-webfonts-helper
# ili ručno s fonts.google.com
# 1. Preuzmite WOFF2 datoteke
# 2. Smjestite ih u /fonts/ direktorij
# 3. Definirajte @font-face u CSS-u
# 4. Postavite caching headere
# Nginx primjer za dugoročno keširanje fontova
# location ~* \.(woff2|woff)$ {
# expires 1y;
# add_header Cache-Control "public, immutable";
# add_header Access-Control-Allow-Origin "*";
# }
Ograničite broj fontova i varijacija
Ovo zvuči očito, ali u praksi se začudite koliko stranica učitava fontove koje ne koristi. Svaka dodatna font datoteka znači dodatni HTTP zahtjev, dodatne kilobajte i potencijalno dodatni pomak rasporeda.
Praktična preporuka:
- Maksimalno 2 font familije — jedna za naslove, jedna za tekst tijela
- Maksimalno 4-6 varijacija ukupno — ili koristite varijabilni font koji pokriva sve
- Izbjegavajte italik varijante ako ih ne koristite aktivno — bolje je koristiti
font-style: obliquesintetički
Svaka font datoteka koja se učitava, a ne koristi na stranici, je čisti gubitak. Napravite audit svojih fontova — možda ćete se iznenaditi koliko nepotrebnih zahtjeva pronađete.
Kompletna implementacija: Sve tehnike zajedno
Dosta teorije — evo cjelovitog primjera koji kombinira sve tehnike iz ovog vodiča na jednom mjestu. Ovo je otprilike template koji koristimo kao polaznu točku na novim projektima:
<!-- HTML: <head> sekcija -->
<link rel="preload"
href="/fonts/Inter-Variable.woff2"
as="font"
type="font/woff2"
crossorigin>
<style>
/* Varijabilni web font — subsetan za latinicu */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: optional;
unicode-range: U+0000-00FF, U+0100-017F;
}
/* Prilagođeni fallback za eliminaciju CLS-a */
@font-face {
font-family: 'Inter Fallback';
src: local('Arial');
size-adjust: 107.64%;
ascent-override: 90.49%;
descent-override: 22.56%;
line-gap-override: 0%;
}
/* Brendirani font za naslove */
@font-face {
font-family: 'Heading';
src: url('/fonts/Heading.woff2') format('woff2');
font-weight: 700;
font-display: swap;
unicode-range: U+0000-00FF, U+0100-017F;
}
body {
font-family: 'Inter', 'Inter Fallback', system-ui, sans-serif;
}
h1, h2, h3 {
font-family: 'Heading', Georgia, serif;
}
</style>
Mjerenje utjecaja: Kako provjeriti jesu li optimizacije uspjele
Optimizacija bez mjerenja je nagađanje. Nakon što primijenite ove tehnike, trebate potvrditi da su zapravo pomogle. Evo JavaScript koda za praćenje font performansi:
// Praćenje utjecaja fontova na performanse
const fontObserver = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
if (entry.initiatorType === 'css' && entry.name.includes('.woff2')) {
console.log('Font:', entry.name);
console.log(' Veličina:', (entry.transferSize / 1024).toFixed(2), 'KB');
console.log(' Trajanje:', entry.duration.toFixed(2), 'ms');
console.log(' TTFB fonta:', (entry.responseStart - entry.requestStart).toFixed(2), 'ms');
}
});
});
fontObserver.observe({ type: 'resource', buffered: true });
// Provjera statusa učitavanja fontova
document.fonts.ready.then(() => {
console.log('Svi fontovi učitani');
document.fonts.forEach(font => {
console.log(` ${font.family}: ${font.status}`);
});
});
Osim toga, provjerite Chrome DevTools Network tab — filtrirajte po "Font" tipu i pogledajte veličine, trajanje i redoslijed preuzimanja. U Lighthouse auditu, posebno obratite pažnju na upozorenja poput "Ensure text remains visible during webfont load" i "Avoid enormous network payloads". Ako ta upozorenja nestanu nakon vaših promjena, na dobrom ste putu.
Često postavljana pitanja (FAQ)
Što je bolje: font-display swap ili optional?
Ovisi o kontekstu. font-display: swap je bolji za brendirane elemente poput logotipa i naslova jer garantira da će se prilagođeni font prikazati čim se preuzme. font-display: optional je bolji za tekst tijela jer eliminira pomake rasporeda (CLS). Naša preporuka je kombinacija oba pristupa — swap za naslove, optional za body tekst.
Koliko web fontova mogu koristiti a da ne usporim stranicu?
Maksimalno 2 font familije i ukupno 4-6 font datoteka. Ako trebate više varijacija, koristite varijabilne fontove koji kombiniraju sve debljine u jednu datoteku. Svaka dodatna font datoteka dodaje otprilike 20-80 KB i jedan HTTP zahtjev.
Trebam li koristiti Google Fonts CDN ili self-hosting?
U 2026. godini, self-hosting je gotovo uvijek bolja opcija. Eliminira DNS i TLS overhead prema vanjskom poslužitelju (ušteda 100-300 ms), omogućuje potpunu kontrolu nad cachingom, osigurava GDPR usklađenost i uklanja ovisnost o trećoj strani. Jedini scenarij gdje Google Fonts CDN još ima smisla je ako nemate kontrolu nad poslužiteljem ili koristite statički hosting bez mogućnosti dodavanja datoteka.
Kako provjeriti uzrokuju li fontovi CLS na mojoj stranici?
Pokrenite PageSpeed Insights i provjerite CLS ocjenu. U Chrome DevTools-u otvorite Performance tab, snimite učitavanje stranice i filtrirajte po "Layout Shift" unosima. Ako vidite pomake povezane s tekstualnim elementima, fontovi su vjerojatno krivac. Za detaljnije praćenje, koristite PerformanceObserver s tipom layout-shift.
Što je font subsetting i koliko može smanjiti veličinu datoteke?
Font subsetting je proces uklanjanja nepotrebnih glifova (znakova) iz font datoteke. Ako vaša stranica koristi samo latinicu, nema razloga učitavati ćirilične, grčke ili azijske glifove. Subsetting može smanjiti veličinu font datoteke za 50-80%, što nije zanemarivo. Za hrvatske web stranice, trebate zadržati Unicode raspone U+0000-00FF (osnovna latinica) i U+0100-017F (proširena latinica A s dijakritičkim znakovima č, ć, š, ž, đ).