Зачем оптимизировать шрифты
Веб-шрифты — одна из самых недооценённых причин медленной загрузки. Типичный Google Fonts — это 2-4 начертания, каждое весом 20-40 КБ. Итого 80-160 КБ шрифтов, которые загружаются до того, как пользователь увидит текст на странице. Плюс DNS-запрос к fonts.googleapis.com, плюс запрос к fonts.gstatic.com — это дополнительные 100-300 мс на мобильных.
Для Core Web Vitals шрифты влияют на два показателя. FCP (First Contentful Paint) задерживается, если браузер ждёт загрузки шрифта, прежде чем отрисовать текст. LCP (Largest Contentful Paint) страдает, если крупнейший элемент — текстовый блок, и он рендерится только после загрузки шрифта.
Существует две проблемы отображения текста при загрузке шрифтов: FOIT и FOUT. FOIT (Flash of Invisible Text) — текст невидим, пока шрифт не загрузится. Пользователь видит пустое место на экране. FOUT (Flash of Unstyled Text) — текст отображается системным шрифтом, а затем перерисовывается кастомным. FOUT предпочтительнее: пользователь сразу видит контент, хоть и с подменой шрифта. FOIT — это потеря времени и ухудшение UX.
Пошаговая инструкция
Шаг 1. Проведите аудит используемых шрифтов
Откройте DevTools → Network, отфильтруйте по типу Font. Посмотрите, сколько файлов шрифтов загружается, их размер и источник. Частые проблемы:
- Загружаются все начертания (100-900), хотя реально используются 2-3
- Загружаются и латиница, и кириллица, и расширенная латиница — хотя сайт только на русском
- Шрифты грузятся с внешнего сервера (fonts.googleapis.com) вместо локального хостинга
- Подключены шрифты, которые вообще не используются в CSS (остались от темы или плагина)
Шаг 2. Добавьте font-display: swap
Это самое быстрое и важное действие. Свойство font-display: swap в объявлении @font-face говорит браузеру: «Показывай текст системным шрифтом сразу, а когда кастомный загрузится — замени». Это устраняет FOIT и ускоряет FCP.
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Если используете Google Fonts через CDN, добавьте параметр display=swap в URL:
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
PageSpeed Insights показывает рекомендацию «Ensure text remains visible during webfont load» именно при отсутствии font-display: swap.
Шаг 3. Перенесите шрифты на свой сервер
Локальный хостинг шрифтов устраняет внешние DNS-запросы и соединения с fonts.googleapis.com / fonts.gstatic.com. Это экономит 100-300 мс, особенно на мобильных.
Как перенести Google Fonts локально:
- Используйте сервис google-webfonts-helper — он генерирует CSS с @font-face и даёт скачать файлы шрифтов.
- Скачайте только нужные начертания и подмножества (charset).
- Разместите файлы в директории темы:
/wp-content/themes/your-theme/fonts/ - Подключите через @font-face в CSS темы, удалив подключение Google Fonts из head.
В WordPress отключить Google Fonts из темы можно через functions.php, деактивировав соответствующий enqueue, или через плагин Perfmatters / Asset CleanUp.
Шаг 4. Используйте только WOFF2
WOFF2 — современный формат шрифтов со встроенным сжатием Brotli. Он на 30% легче WOFF и поддерживается всеми актуальными браузерами. WOFF, TTF, EOT, SVG — устаревшие форматы, их можно безопасно убрать. Единственное исключение — если нужна поддержка IE 11, но его доля трафика в 2026 году близка к нулю.
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Шаг 5. Создайте подмножество шрифта (subsetting)
Полный файл шрифта содержит глифы для всех языков: латиница, кириллица, греческий, арабский, иероглифы. Для русскоязычного сайта нужны только кириллица и базовая латиница (для URL, английских терминов). Subsetting удаляет ненужные глифы и уменьшает файл в 2-5 раз.
Инструменты для subsetting:
- pyftsubset (из библиотеки fonttools) — CLI-инструмент для точного контроля:
pyftsubset font.ttf --unicodes="U+0400-04FF,U+0020-007F" --flavor=woff2 - glyphhanger — анализирует реальные страницы сайта и определяет, какие символы действительно используются
- google-webfonts-helper — при скачивании можно выбрать только нужные charset
Шаг 6. Настройте предзагрузку критических шрифтов
Браузер начинает загрузку шрифта только после парсинга CSS и обнаружения @font-face. Предзагрузка (preload) говорит браузеру: «Начни скачивать шрифт прямо сейчас, не дожидаясь CSS».
<link rel="preload" href="/fonts/roboto-regular.woff2" as="font" type="font/woff2" crossorigin>
Важно: предзагружайте только 1-2 критических начертания (обычно regular и bold). Если предзагрузить все 5 файлов — вы конкурируете с загрузкой CSS, JS и изображений, и суммарная скорость не улучшится. Атрибут crossorigin обязателен даже для локальных шрифтов — без него браузер загрузит шрифт дважды.
Шаг 7. Рассмотрите системный стек шрифтов
Самый радикальный вариант оптимизации — отказаться от веб-шрифтов вообще. Системный стек шрифтов загружается за 0 мс, потому что шрифты уже установлены на устройстве пользователя:
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
На macOS/iOS пользователь увидит San Francisco, на Windows — Segoe UI, на Android — Roboto. Все эти шрифты хорошо читаемые и современные. Для блога или корпоративного сайта системный стек — отличный выбор. Для бренда с жёсткими гайдлайнами по типографике — возможно, не подойдёт.
Типичные ошибки
- Подключать 5+ начертаний «на всякий случай». Thin (100), Light (300), Regular (400), Medium (500), SemiBold (600), Bold (700), Black (900) — каждое начертание это отдельный файл. Для большинства сайтов достаточно Regular (400) и Bold (700). Если нужен Light — добавьте, но 5+ начертаний — это избыточность.
- Использовать font-display: optional вместо swap. Optional сокращает FOIT, но может вообще не показать кастомный шрифт при медленном соединении — текст останется системным навсегда. Для брендинга это неприемлемо. Swap — оптимальный баланс.
- Предзагружать шрифты с внешнего домена без crossorigin. Шрифты всегда запрашиваются в анонимном CORS-режиме. Без атрибута crossorigin в теге preload браузер загрузит шрифт дважды: один раз по preload (без CORS), второй раз — по @font-face (с CORS). Первая загрузка пропадает впустую.
- Забывать удалить подключение Google Fonts после локализации. Скачали шрифты, прописали @font-face, но старый link на fonts.googleapis.com остался в head. Браузер грузит шрифты дважды — и локально, и с CDN.
- Не учитывать вариативные шрифты. Variable fonts содержат все начертания в одном файле. Roboto Flex variable — один файл 100 КБ вместо 5 файлов по 25 КБ. Если нужно 3+ начертания, вариативный шрифт может быть легче, чем отдельные файлы.
Что проверить в итоге
- В DevTools → Network → Font загружаются только нужные начертания (обычно 2-3 файла).
- Все шрифты в формате WOFF2 (нет TTF, WOFF, EOT).
- В @font-face указано font-display: swap для всех шрифтов.
- Шрифты загружаются с собственного домена, а не с fonts.googleapis.com.
- Критические шрифты (1-2 файла) предзагружены через link rel=»preload».
- Файлы шрифтов содержат только нужные подмножества (кириллица + базовая латиница).
- Нет дублирования загрузки (шрифт не грузится и локально, и с CDN одновременно).
- PageSpeed Insights не показывает рекомендацию «Ensure text remains visible during webfont load».