Веб-шрифты без ожидания: font-display, сабсеты и preload
Невидимый текст, прыгающая вёрстка и лишний домен для каждого посетителя — как подключать свои шрифты так, чтобы текст появлялся сразу и не съезжал.
Производительность · Опубликовано: 2 октября 2026 г. · 7 мин чтения · Марк Лебедев
Свой шрифт — обычно самая крупная часть дизайна, которая блокирует текст. Пока он не загрузился, браузеру приходится решать, что делать с каждым заголовком и абзацем на странице: спрятать их или показать чем-то другим. У обоих вариантов есть цена, и настройки по умолчанию редко выбирают за вас более дешёвый.
FOIT, FOUT и за что отвечает font-display
FOIT — flash of invisible text, вспышка невидимого текста — это когда браузер прячет текст, пока качается шрифт. На медленном соединении у страницы есть сетка, картинки и кнопки, но нет ни одного слова. FOUT — flash of unstyled text — обратная ситуация: текст сразу рисуется запасным шрифтом и подменяется, когда приходит веб-шрифт.
Выбор между ними делает дескриптор font-display в @font-face. Он задаёт короткий *период блокировки* (текст невидим) и *период замены* (виден запасной шрифт, но веб-шрифт ещё может его заменить):
auto(по умолчанию) иblock— на практике блокировка до трёх секунд. Это и есть FOIT, которого стоит избегать.swap— почти нулевая блокировка и бесконечный период замены. Текст сразу появляется запасным шрифтом, а веб-шрифт подменяет его, когда бы ни загрузился. Безопасный выбор по умолчанию для основного текста и заголовков.fallback— блокировка около 100 мс и период замены около трёх секунд. Если шрифт опоздал, страница до конца визита остаётся с запасным. Хороший компромисс, когда поздняя подмена мешает сильнее, чем другая гарнитура.optional— блокировка около 100 мс и никакого периода замены. Браузер использует веб-шрифт, только если он доступен почти мгновенно — обычно из кеша, — иначе остаётся запасной. Никаких сдвигов вёрстки из-за шрифтов, но новые посетители на медленной сети вашу гарнитуру так и не увидят.
swap жертвует визуальной стабильностью ради видимого текста, optional — фирменным шрифтом ради стабильности. Для большинства сайтов разумная отправная точка — swap для текстовых шрифтов и optional для декоративных.
Меньше файлов, меньше байтов
Только WOFF2. Его поддерживают все браузеры, которыми сейчас пользуются, а сжатие на основе Brotli заметно выигрывает у WOFF и TTF. Запасные .woff, .ttf и .eot в src ничего не дают, кроме лишней поддержки.
Сабсеты. Полный шрифт с латиницей, кириллицей, греческим и вьетнамским может весить в разы больше, чем нужно одной странице. Разбейте его на подмножества и дайте unicode-range подсказать браузеру, какой файл качать: подмножество загружается, только если на странице действительно есть символы из этого диапазона.
@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;
}
Английская страница никогда не скачает кириллический файл, а русская получит оба — латинские цифры и знаки препинания в ней всё равно есть.
Ограничьте начертания. Обычный, жирный и курсив в двух семействах — это уже шесть файлов. Спросите себя, правда ли дизайну нужны 300 и 600. Если нужны, помогают вариативные шрифты: один файл покрывает всю ось насыщенности (font-weight: 100 900). Вариативный файл обычно тяжелее одного статического начертания, поэтому он окупается примерно с трёх начертаний, а не с одного.
Свой хостинг вместо стороннего CDN шрифтов
Подключение через Google Fonts — это стилевой файл с fonts.googleapis.com, а затем сами шрифты с fonts.gstatic.com: два лишних домена, у каждого свой DNS-запрос, TCP- и TLS-рукопожатие, и обнаруживаются они только после разбора вашего HTML и CSS. Старый довод «у посетителя шрифт уже в кеше с другого сайта» больше не работает: все основные браузеры теперь разделяют HTTP-кеш по сайту верхнего уровня, так что шрифт, закешированный на одном сайте, на вашем скачивается заново.
Шрифты на своём хостинге лежат на том же домене, с которым браузер уже соединён, вы сами управляете сабсетами и заголовками кеширования, а из каждого просмотра страницы уходит сторонний запрос. Лицензия шрифта обычно это разрешает, но проверьте, прежде чем копировать.
Preload для одного-двух главных
Браузер узнаёт о шрифте, только когда у него есть CSS и он нашёл текст, который этот шрифт использует. Preload запускает загрузку раньше:
<link rel="preload" href="/fonts/inter-latin.woff2"
as="font" type="font/woff2" crossorigin>
Атрибут crossorigin обязателен даже для шрифтов со своего домена: шрифты запрашиваются в режиме CORS, и preload без него не совпадёт с настоящим запросом — файл скачается дважды. Предзагружайте только шрифт, который виден на первом экране, — обычно основную текстовую гарнитуру в одном сабсете. Предзагрузка всех начертаний конкурирует за канал с CSS и главной картинкой и делает страницу медленнее, а не быстрее.
Запасной шрифт того же размера
При swap в момент подмены запасного шрифта веб-шрифтом строки переносятся заново, а блоки меняют высоту. Это сдвиг вёрстки, и он идёт в CLS. Переопределение метрик позволяет подогнать локальный шрифт под пропорции веб-шрифта:
@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; }
Числа выше условные: рассчитайте их для своего шрифта инструментом вроде Capsize или Fontaine или доверьте генерацию фреймворку. Если всё сделано хорошо, подмена становится почти незаметной.
Кеш на год
Файлы шрифтов идеально подходят для долгого кеширования. Добавьте версию или хеш в имя файла и отдавайте:
Cache-Control: public, max-age=31536000, immutable
Если шрифты лежат на отдельном CDN-домене, он должен ещё и отдавать Access-Control-Allow-Origin, иначе браузер откажется их использовать.
Отчёт SiteScan проверяет одну часть из этого: помечает веб-шрифты, объявленные без font-display, и советует задать font-display: swap.
Чек-лист
- У каждого
@font-faceявно заданfont-display. - Шрифты отдаются только в WOFF2.
- Файлы разбиты на сабсеты с
unicode-range. - Загружаются только те начертания, что есть в дизайне; при большом их числе — вариативный шрифт.
- Шрифты лежат на вашем собственном домене.
- Один-два критичных шрифта предзагружены с
crossorigin. - У запасного шрифта переопределены метрики, чтобы ограничить сдвиг вёрстки.
- У файлов шрифтов версионированные имена и неизменяемый кеш на год.
Читайте также
Проверьте, что из этого есть на вашем сайте
Бесплатное сканирование покажет битые ссылки, ошибки JS и проблемы производительности за минуту.