Przejdź do treści głównej
SiteScan.top

Fonty webowe bez czekania: font-display, subsety i preload

Niewidoczny tekst, skaczący układ i dodatkowa domena dla każdego odwiedzającego — jak ładować własne fonty, żeby tekst pojawiał się od razu i nie przeskakiwał.

Wydajność · Opublikowano: 2 października 2026 · 7 min czytania · Марк Лебедев

Własny font to zwykle największy element projektu, który blokuje tekst. Dopóki nie dotrze, przeglądarka musi zdecydować, co zrobić z każdym nagłówkiem i akapitem na stronie: ukryć je albo pokazać czymś innym. Obie opcje mają swoją cenę, a ustawienia domyślne rzadko wybierają za ciebie tę tańszą.

FOIT, FOUT i za co odpowiada font-display

FOIT — flash of invisible text, błysk niewidocznego tekstu — to przeglądarka ukrywająca tekst, dopóki font się pobiera. Na wolnym łączu strona ma układ, obrazki i przyciski, ale ani jednego słowa. FOUT — flash of unstyled text — to sytuacja odwrotna: tekst od razu rysowany jest fontem zastępczym i podmieniany, gdy przyjdzie font webowy.

Wybór między nimi należy do deskryptora font-display w @font-face. Definiuje on krótki *okres blokady* (tekst niewidoczny) i *okres zamiany* (widoczny font zastępczy, ale font webowy wciąż może go zastąpić):

swap poświęca stabilność wizualną na rzecz widocznego tekstu, optional — font firmowy na rzecz stabilności. Dla większości witryn rozsądny punkt wyjścia to swap dla fontów tekstowych i optional dla dekoracyjnych.

Mniej plików, mniej bajtów

Tylko WOFF2. Obsługuje go każda używana dziś przeglądarka, a kompresja oparta na Brotli wyraźnie wygrywa z WOFF i TTF. Zapasowe .woff, .ttf i .eot w src nie dają nic poza dodatkową konserwacją.

Subsety. Pełny font z alfabetem łacińskim, cyrylicą, greką i wietnamskim może ważyć kilka razy więcej, niż potrzebuje jedna strona. Podziel go na podzbiory i pozwól, by unicode-range podpowiedział przeglądarce, który plik pobrać — subset jest ładowany tylko wtedy, gdy na stronie rzeczywiście są znaki z tego zakresu:

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-cyrillic.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

Strona angielska nigdy nie pobierze pliku z cyrylicą, a rosyjska dostanie oba, bo i tak używa łacińskich cyfr i znaków interpunkcyjnych. Uwaga dla polskich stron: litery takie jak „ą”, „ę” czy „ł” leżą poza zakresem U+0000-00FF, więc subset łaciński musi obejmować też Latin Extended-A (U+0100-017F).

Ogranicz odmiany. Regular, bold i italic w dwóch rodzinach to już sześć plików. Zapytaj, czy projekt naprawdę potrzebuje 300 i 600. Jeśli tak, pomagają fonty zmienne: jeden plik obejmuje całą oś grubości (font-weight: 100 900). Plik zmienny jest zwykle większy niż jedna statyczna odmiana, więc opłaca się mniej więcej od trzech odmian w górę, nie przy jednej.

Własny hosting zamiast zewnętrznego CDN z fontami

Ładowanie z Google Fonts to arkusz stylów z fonts.googleapis.com, a potem pliki fontów z fonts.gstatic.com — dwie dodatkowe domeny, każda z własnym zapytaniem DNS, handshake'iem TCP i TLS, odkrywane dopiero po sparsowaniu twojego HTML i CSS. Stary argument, że odwiedzający ma już font w cache z innej witryny, przestał działać: wszystkie główne przeglądarki dzielą teraz cache HTTP według witryny najwyższego poziomu, więc font zapisany na jednej stronie jest pobierany ponownie na twojej.

Własny hosting umieszcza pliki na domenie, z którą przeglądarka i tak jest już połączona, daje kontrolę nad subsetami i nagłówkami cache i usuwa zewnętrzne żądanie z każdej odsłony. Licencja fontu zwykle na to pozwala, ale sprawdź, zanim skopiujesz.

Preload dla jednego-dwóch najważniejszych

Przeglądarka dowiaduje się o foncie dopiero wtedy, gdy ma CSS i znajdzie tekst, który go używa. Preload uruchamia pobieranie wcześniej:

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

Atrybut crossorigin jest wymagany nawet dla fontów z tej samej domeny: fonty pobierane są w trybie CORS, a preload bez niego nie pasuje do prawdziwego żądania, więc plik pobiera się dwa razy. Preloaduj tylko font widoczny na pierwszym ekranie — zwykle główny krój tekstowy w jednym subsecie. Preload wszystkich odmian konkuruje o pasmo z CSS i głównym obrazem i spowalnia stronę zamiast ją przyspieszać.

Font zastępczy w tym samym rozmiarze

Przy swap w chwili, gdy font webowy zastępuje zastępczy, wiersze łamią się na nowo, a bloki zmieniają wysokość. To przesunięcie układu i liczy się do CLS. Nadpisanie metryk pozwala dopasować lokalny font do proporcji fontu webowego:

@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}
body { font-family: "Inter", "Inter Fallback", sans-serif; }

Powyższe liczby są poglądowe: oblicz je dla swojego fontu narzędziem takim jak Capsize czy Fontaine albo pozwól wygenerować je frameworkowi. Dobrze zrobiona podmiana staje się niemal niezauważalna.

Cache na rok

Pliki fontów idealnie nadają się do długiego cache. Dodaj wersję lub hash do nazwy pliku i serwuj:

Cache-Control: public, max-age=31536000, immutable

Jeśli fonty leżą na osobnej domenie CDN, musi ona także wysyłać Access-Control-Allow-Origin, inaczej przeglądarka odmówi ich użycia.

Raport SiteScan sprawdza jeden element z tej listy: oznacza fonty webowe zadeklarowane bez font-display i sugeruje ustawienie font-display: swap.

Lista kontrolna

  1. Każdy @font-face ma jawnie ustawione font-display.
  2. Fonty serwowane są wyłącznie jako WOFF2.
  3. Pliki podzielone są na subsety z unicode-range.
  4. Ładowane są tylko odmiany używane w projekcie; przy wielu — font zmienny.
  5. Fonty hostowane są na twojej własnej domenie.
  6. Jeden lub dwa krytyczne fonty mają preload z crossorigin.
  7. Font zastępczy ma nadpisane metryki, żeby ograniczyć przesunięcia układu.
  8. Pliki fontów mają wersjonowane nazwy i niezmienny cache na rok.

Przeczytaj także

Sprawdź, ile z tego dotyczy Twojej strony

Darmowe skanowanie pokaże uszkodzone linki, błędy JS i problemy z wydajnością w minutę.