Opóźnione pojawianie się tekstu, nagła zmiana kroju pisma w trakcie czytania czy gwałtowne przeskoczenie elementów interfejsu podczas ładowania strony to powszechne błędy związane z nieoptymalną obsługą czcionek webowych (Web Fonts). Pobieranie zewnętrznych plików z krojami pisma często blokuje renderowanie czytelnej treści, negatywnie wpływając na odczucia użytkownika oraz wskaźniki wydajności.
Prawidłowe skonfigurowanie strategii pobierania czcionek pozwala wyeliminować efekt niepotrzebnego znikania tekstu oraz zabezpieczyć stronę przed niekontrolowanymi przesunięciami układu (Layout Shifts).
FOIT vs FOUT – z czym tak naprawdę się zmagamy?
Gdy przeglądarka napotyka w pliku CSS regułę @font-face z czcionką zewnętrzną, musi podjąć decyzję, co wyświetlić użytkownikowi w czasie, gdy plik .woff2 jest jeszcze pobierany przez sieć. W zależności od przeglądarki i konfiguracji dochodzi do dwóch negatywnych zjawisk:
- FOIT (Flash of Invisible Text): Przeglądarka ukrywa tekst, wyświetlając puste miejsce, dopóki czcionka sieciowa nie zostanie w pełni pobrana i przetworzona. Użytkownik patrzy na białą plamę w miejscu nagłówków lub treści artykułu.
- FOUT (Flash of Unstyled Text): Przeglądarka natychmiast wyświetla tekst przy użyciu czcionki systemowej (fallback font), a po pobraniu docelowego pliku zamienia krój na właściwy. Zjawisko to bywa nieprzyjemne dla oka, jeśli czcionki różnią się szerokością i wysokością znaków.
Ukrywanie tekstu (FOIT) bezpośrednio opóźnia renderowanie głównych elementów treści, co drastycznie pogarsza czas oczekiwania na pierwsze wyrenderowanie tekstu – więcej o tej metryce przeczytasz w poradniku wyjaśniającym, jak podejść do zagadnienia, jakim jest optymalizacja LCP w nowoczesnych aplikacjach.
Sterowanie zachowaniem przeglądarki za pomocą font-display
Kluczowym narzędziem w CSS służącym do kontrolowania procesu ładowania czcionek jest dyrektywa font-display dodawana do bloku @font-face. Definiuje ona tzw. osiem czasu (timeline), podzielony na okres blokowania i okres zamiany:
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font.woff2') format('woff2');
font-display: swap;
font-weight: 400;
font-style: normal;
}
Wartości dyrektywy font-display i ich wpływ na interfejs:
swap(Zalecane dla treści): Okres blokowania wynosi niemal 0ms – przeglądarka od razu renderuje tekst czcionką systemową (FOUT), a po pobraniu pliku wykonuje bezproblemową zamianę. Tekst jest czytelny od pierwszej sekundy.optional(Zalecane przy słabych połączeniach): Daje czcionce bardzo krótki czas na pobranie (ok. 100ms). Jeśli plik nie zdąży się pobrać, przeglądarka używa czcionki systemowej dla całej sesji, a pobrany plik zapisuje w cache na przyszłość. Zapobiega to przeskakiwaniu tekstu w trakcie czytania.block: Długi okres blokowania (do 3s). Powoduje drastyczny efekt FOIT i nie jest zalecany dla tekstu podstawowego.
Wstępne pobieranie krytycznych plików czcionek (Preload)
Domyślnie przeglądarka odkrywa potrzebę pobrania czcionki stosunkowo późno: najpierw pobiera plik HTML, potem parsuje CSS, dopasowuje reguły do węzłów DOM i dopiero gdy ustali, że dany tekst na stronie rzeczywiście używa kroju z @font-face, inicjuje połączenie sieciowe.
Możesz drastycznie przyspieszyć ten proces, dodając w sekcji <head> tag <link rel="preload"> dla kluczowych wariantów czcionek (np. nagłówków lub głównego kroju artykułu):
<link rel="preload" href="/fonts/custom-font.woff2" as="font" type="font/woff2" crossorigin>
Atrybut crossorigin jest obowiązkowy przy ładowaniu czcionek – bez niego przeglądarka pobierze plik dwukrotnie, marnując pasmo sieciowe.
Dopasowanie metryk czcionki systemowej (Font Metric Overrides)
Samo użycie font-display: swap eliminuje niewidzialny tekst, ale wprowadzany w ten sposób efekt FOUT może wywołać niepożądane skoki układu (CLS - Cumulative Layout Shift), gdy czcionka systemowa (np. Arial) ma inne proporcje niż wczytywana czcionka niestandardowa.
Nowoczesny CSS pozwala wygładzić ten proces poprzez dostosowanie wymiarów czcionki rezerwowej za pomocą właściwości size-adjust, ascent-override oraz descent-override:
@font-face {
font-family: 'FallbackFont';
src: local('Arial');
ascent-override: 90%;
descent-override: 20%;
size-adjust: 98%;
}
body {
font-family: 'CustomFont', 'FallbackFont', sans-serif;
}
Dzięki dopasowaniu skali i wysokości linii czcionka systemowa zajmuje dokładnie tyle samo miejsca, co docelowa czcionka sieciowa. Podmieniający się krój pisma nie powoduje przesunięcia sąsiednich blokerów i tekstu w dół strony.
Szybkie serwowanie i podcinanie zakresów znaków (Subsetting)
Ostatnim filarem optymalizacji jest redukcja wagi samego pliku czcionki. Standardowy plik czcionki często zawiera glify dla dziesiątek języków, symbole i znaki specjalne, ważąc nawet ponad 200 KB.
Korzystając z mechanizmu unicode-range w CSS lub wycinając nieużywane znaki na etapie budowania (za pomocą narzędzi takich jak glyphhanger czy pyftsubset), można ograniczyć plik do zestawu znaków łacińskich i polskich (np. do 15-20 KB), serwując go w ultra-wydajnym formacie WOFF2 z własnego CDN-a.
Trzymając się tych zasad, eliminujesz irytujące mignięcia ekranu, a strona dostarcza natychmiast czytelną treść, dbając o wzorowy UX od pierwszej klatki renderowania.