Шрифты — одна из тех вещей, на которые обычно не обращают внимания при оптимизации, а потом удивляются, почему PageSpeed показывает 55 баллов вместо 90+. За 10 лет работы с сайтами на Bitrix, WordPress и Laravel я видел десятки проектов, где именно неправильно подключённые шрифты убивали скорость загрузки.
Почему шрифты убивают скорость загрузки
Честно говоря, проблема шрифтов недооценена. Большинство разработчиков думают: "Ну, это же просто CSS и пара файлов". На деле один неправильно подключённый Google Fonts может добавить 500–800 мс к Time to First Byte и полностью заблокировать рендеринг страницы. Я видел сайты, где из-за одного тега <link> на Google Fonts показатель LCP (Largest Contentful Paint) улетал за 4 секунды.
Механика простая: браузер парсит HTML, встречает тег подключения шрифта, делает DNS-запрос к сторонним серверам (fonts.googleapis.com, fonts.gstatic.com), ждёт ответа, скачивает CSS-файл с описанием @font-face, потом идёт за самими файлами шрифтов. Пока всё это происходит — текст либо не отображается вообще (FOIT, Flash of Invisible Text), либо показывается в системном шрифте, а потом резко меняется (FOUT, Flash of Unstyled Text). Оба варианта плохо влияют на CLS (Cumulative Layout Shift) и на восприятие пользователем.
Отдельная боль — это когда подключают 5–6 начертаний шрифта там, где реально используется 2–3. У одного клиента я нашёл подключение Roboto в вариантах 100, 300, 400, 500, 700, 900 — и это для корпоративного сайта с минимальной типографикой. Каждый вариант — отдельный файл, отдельный запрос. Это плохая идея.
Форматы шрифтов: что использовать в 2026
Забудьте про TTF и EOT. В 2026 году это архаика. TTF-файлы огромные, EOT вообще был нужен только для IE6–8. Рабочий стек сейчас — это WOFF2 как основной формат и WOFF как запасной для совсем старых браузеров.
WOFF2 использует алгоритм сжатия Brotli на уровне кодека шрифтов. В среднем WOFF2 на 30–40% легче TTF того же шрифта. Для примера: Roboto Regular в TTF весит около 168 КБ, в WOFF2 — примерно 65 КБ. Разница ощутимая, особенно когда шрифтов несколько.
Если нужна поддержка совсем старых браузеров (IE11, старые Android), то схема такая: сначала WOFF2, потом WOFF. Всё. Никаких TTF в production. Вот как выглядит правильный @font-face:
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-regular.woff2') format('woff2'),
url('/fonts/myfont-regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
Параметр unicode-range — это отдельная история, о которой ниже. А пока обратите внимание на font-display: swap. Это ключевой параметр для борьбы с FOIT.
woff2_compress от Google или онлайн-сервис FontSquirrel Webfont Generator. Второй вариант удобнее, но первый даёт больше контроля над результатом.font-display: управляем отображением текста
Это свойство появилось давно, но многие до сих пор его игнорируют. font-display определяет поведение браузера в момент, когда шрифт ещё не загружен. У него пять значений, и каждое имеет смысл в определённой ситуации.
swap — самый распространённый выбор. Браузер сразу показывает текст в системном шрифте, а когда основной шрифт загрузится — подменяет. Это убирает FOIT, но может создать заметный FOUT. Для большинства сайтов — оптимальный вариант. Именно его рекомендует Google для улучшения Core Web Vitals.
optional — браузер даёт шрифту очень короткий таймаут (около 100 мс). Если за это время шрифт не загрузился — используется системный шрифт навсегда (для текущей загрузки страницы). Шрифт при этом всё равно скачивается в фоне и будет использован при следующем визите (если закешировался). Это лучший выбор для перформанса, особенно на медленных соединениях. Но нужно подбирать похожий системный шрифт.
block — браузер блокирует отображение текста на 3 секунды, ожидая шрифт. Это классический FOIT. Используйте только для иконочных шрифтов, где системная замена невозможна. Для текстового контента — плохая идея.
fallback — компромисс между swap и optional. Очень короткий блок (100 мс), потом бесконечный период подмены. Хорошо работает для второстепенных шрифтов.
auto — поведение определяет браузер. На практике обычно равно block. Избегайте этого значения.
По моему опыту: для основного шрифта сайта используйте swap, для декоративных заголовочных шрифтов — optional, для иконочных — block. Такая комбинация даёт хороший баланс между визуальным результатом и скоростью.
Самохостирование шрифтов vs Google Fonts
Вот тема для холивара. Я однозначно за самохостирование шрифтов в production. Объясню почему.
Во-первых, сторонний запрос — это всегда DNS lookup + TCP handshake + TLS negotiation. Даже с preconnect это занимает 50–150 мс. На медленных мобильных соединениях — больше. Ваш сервер вы уже знаете, браузер уже к нему подключён. Это экономия времени.
Во-вторых, с 2022 года немецкие суды признали использование Google Fonts через CDN нарушением GDPR, поскольку IP пользователя передаётся на серверы Google без явного согласия. В России это может быть неактуально прямо сейчас, но для международных проектов — серьёзный аргумент.
В-третьих, Google Fonts недоступны из некоторых регионов или корпоративных сетей с жёсткими файерволами. Самохостированный шрифт всегда доступен.
Единственный плюс Google Fonts — потенциальный кеш браузера. Раньше считалось, что если пользователь уже посещал другой сайт с тем же Google Font, шрифт закеширован. Но с 2020 года Chrome изолирует кеш по происхождению (cache partitioning), так что этот аргумент больше не работает.
Скачать шрифты с Google Fonts легально и бесплатно можно через сервис google-webfonts-helper.herokuapp.com. Там же генерируется готовый CSS с @font-face. Я пользуюсь им постоянно.
preload и preconnect: правильное использование
Это инструменты для ускорения загрузки шрифтов на уровне HTML. Используются неправильно в 80% случаев, которые я видел.
preconnect нужен, если вы всё-таки используете сторонние шрифты (Google Fonts, Typekit). Он говорит браузеру: "Заранее установи соединение с этим доменом". Для Google Fonts нужно два тега — для fonts.googleapis.com и fonts.gstatic.com:
<!-- Для Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Для самохостированного шрифта -->
<link rel="preload"
href="/fonts/roboto-regular.woff2"
as="font"
type="font/woff2"
crossorigin>
preload — более агрессивный инструмент. Он говорит браузеру: "Скачай этот файл немедленно, с высоким приоритетом, он точно понадобится". Используйте preload только для критически важных шрифтов — того, который используется в заголовке первого экрана или в основном тексте. Если сделать preload для всех 6 начертаний, вы просто создадите конкуренцию за пропускную способность с другими критическими ресурсами.
На практике я обычно делаю preload для 1–2 шрифтов: основного текстового и заголовочного. Остальные загружаются в обычном порядке через @font-face. Это даёт хороший баланс — критический текст рендерится быстро, остальные шрифты не мешают загрузке.
Кстати, если вы работаете с Nginx, можно настроить HTTP/2 Server Push для шрифтов. Но с появлением 103 Early Hints этот подход стал ещё более эффективным. Подробнее об этом писал в статье про настройку HTTP/2 и HTTP/3.
Subsetting: режем шрифт до нужных символов
Это моя любимая оптимизация. Большинство коммерческих шрифтов содержат символы для десятков языков — греческий, арабский, кириллица, латиница, математические символы, специальные символы. Если ваш сайт только на русском и английском — зачем платить за загрузку всего этого?
Subsetting — это создание урезанной версии шрифта, содержащей только нужные символы. Инструмент — pyftsubset из пакета fonttools (Python). Установка: pip install fonttools brotli.
# Установка
pip install fonttools brotli zopfli
# Создание subset для русского и английского языков
pyftsubset roboto-regular.ttf \
--output-file="roboto-regular-subset.woff2" \
--flavor=woff2 \
--layout-features="kern,liga,calt" \
--unicodes="U+0000-00FF,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116,U+2013-2014"
# Результат: вместо 168 КБ получаем 35-45 КБ
Параметр --unicodes задаёт диапазоны Unicode. Для типичного русскоязычного сайта достаточно: базовая латиница (U+0000-00FF), кириллица (U+0400-045F), и несколько специальных символов вроде номера (№, U+2116) и тире (U+2013-2014).
Параметр --layout-features сохраняет OpenType-фичи: kern (кернинг), liga (лигатуры), calt (контекстные альтернативы). Если убрать их — шрифт будет выглядеть хуже типографически, но будет чуть легче.
У меня был случай с интернет-магазином на Bitrix — подключали Montserrat и PT Sans, оба в полных версиях. После subsetting суммарный вес шрифтов упал с 480 КБ до 95 КБ. PageSpeed на мобильных вырос с 62 до 81 балла только за счёт этой оптимизации.
Параметр unicode-range в @font-face работает в связке с subsetting. Если разбить шрифт на несколько subset-файлов (латиница отдельно, кириллица отдельно), браузер скачает только тот файл, символы из которого реально встречаются на странице. Так делает Google Fonts — это одна из причин, почему их шрифты загружаются относительно быстро.
Variable Fonts: будущее уже наступило
Variable Fonts (вариативные шрифты) — это один файл шрифта, который содержит весь диапазон начертаний: от тонкого до жирного, от узкого до широкого, от обычного до курсивного. Вместо того чтобы загружать Roboto 400, Roboto 700 и Roboto Italic отдельно — загружаете один файл Roboto Variable и управляете всем через CSS.
Поддержка браузерами отличная: Chrome 66+, Firefox 62+, Safari 11+, Edge 17+. В 2026 году это уже не экспериментальная технология — это стандарт.
/* Подключение variable font */
@font-face {
font-family: 'RobotoVariable';
src: url('/fonts/Roboto-VariableFont_wdth,wght.woff2') format('woff2-variations');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
/* Использование */
h1 {
font-family: 'RobotoVariable', sans-serif;
font-weight: 700;
}
p {
font-family: 'RobotoVariable', sans-serif;
font-weight: 400;
}
/* Анимация веса (можно делать плавные переходы!) */
.animated-text {
font-family: 'RobotoVariable', sans-serif;
font-variation-settings: 'wght' 400;
transition: font-variation-settings 0.3s ease;
}
.animated-text:hover {
font-variation-settings: 'wght' 700;
}
Один variable font файл обычно весит больше, чем один обычный файл того же шрифта. Но если вам нужно 3+ начертания — variable font будет легче суммарно. Roboto Variable WOFF2 весит около 80 КБ, но заменяет 3–4 отдельных файла суммарным весом 150–200 КБ. Выгода очевидна.
Не все шрифты существуют в variable-версии, но популярные — уже да. Inter Variable, Roboto Variable, Source Sans Variable, Nunito Variable — всё это доступно бесплатно.
Настройка кэширования шрифтов на сервере
Шрифты не меняются. Никогда. Если вы обновили файл шрифта — это по сути новый шрифт с новым именем. Поэтому кэшировать их нужно агрессивно — на год вперёд. Это стандартная практика.
Конфигурация для Nginx:
server {
# ...
# Кэширование шрифтов на 1 год
location ~* \.(woff2|woff|ttf|otf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable, max-age=31536000";
add_header Access-Control-Allow-Origin "*";
# Включаем gzip/brotli для woff (woff2 уже сжат)
gzip_static on;
brotli_static on;
}
}
Заголовок Access-Control-Allow-Origin нужен обязательно. Браузеры применяют CORS к шрифтам, и без этого заголовка шрифт с вашего CDN может не загрузиться. Я сталкивался с этим несколько раз — перенесли шрифты на поддомен для CDN, всё работало локально, а на production шрифты не загружались. Причина — CORS. Подробнее про настройку заголовков CORS можно почитать в отдельном руководстве.
Для Apache (.htaccess) аналогичная конфигурация:
<FilesMatch "\.(woff2|woff|ttf|otf|eot)$">
Header set Cache-Control "public, immutable, max-age=31536000"
Header set Expires "Thu, 31 Dec 2026 23:59:59 GMT"
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
Если используете CDN — убедитесь, что правила кэширования распространяются и на шрифтовые файлы. Некоторые CDN по умолчанию не кэшируют файлы без явного Cache-Control от origin. Детальнее о настройке CDN я разбирал в статье про кэширование статики и CDN.
Оптимизация шрифтов в WordPress и Bitrix
Тема отдельная, потому что CMS добавляют свои шрифты поверх ваших. WordPress подключает Inter для блочного редактора. Многие темы тащат Google Fonts через wp_enqueue_style. Плагины тоже любят добавить "свой" шрифт.
Для WordPress: первым делом я смотрю в DevTools Network на все запросы к fonts.googleapis.com. Потом ищу, откуда они приходят — из темы или из плагина. В functions.php темы часто есть что-то вроде:
<?php
// Отключаем Google Fonts из темы (добавить в functions.php)
function remove_google_fonts() {
// Замените 'twentytwentyfour-fonts' на handle вашей темы
wp_dequeue_style('twentytwentyfour-fonts');
wp_deregister_style('twentytwentyfour-fonts');
}
add_action('wp_enqueue_scripts', 'remove_google_fonts', 100);
// Отключаем шрифт блочного редактора
function remove_wp_block_font() {
wp_dequeue_style('wp-block-library');
// Осторожно: это отключает весь стиль блоков, не только шрифты
}
// Подключаем локальный шрифт
function enqueue_local_fonts() {
wp_enqueue_style(
'local-roboto',
get_template_directory_uri() . '/fonts/roboto.css',
[],
'1.0.0'
);
}
add_action('wp_enqueue_scripts', 'enqueue_local_fonts');
?>
Плагин OMGF (Optimize My Google Fonts) делает это автоматически — скачивает шрифты локально, добавляет preload и меняет font-display. Для большинства WordPress-проектов это быстрое решение. Я обычно использую его как стартовую точку, а потом дочищаю вручную.
В Bitrix ситуация немного другая. Стандартные шаблоны Bitrix используют системные шрифты или собственные. Проблемы чаще приходят от сторонних шаблонов с MarketPlace или от разработчиков, которые накидали Google Fonts прямо в template.php. Ищите подключение шрифтов в header.php шаблона и в компонентах. Если нужна профессиональная оптимизация Bitrix-сайта — могу помочь в рамках поддержки Bitrix.
System Font Stack: когда шрифты вообще не нужны
Радикальный, но иногда правильный подход. System Font Stack — это набор системных шрифтов, которые уже установлены на устройстве пользователя. Никаких загрузок, никаких FOIT/FOUT, мгновенный рендеринг.
body {
font-family:
-apple-system, /* macOS/iOS: San Francisco */
BlinkMacSystemFont, /* Chrome на macOS: San Francisco */
'Segoe UI', /* Windows 10+: Segoe UI */
'Roboto', /* Android: Roboto */
'Oxygen', /* KDE Linux */
'Ubuntu', /* Ubuntu Linux */
'Cantarell', /* GNOME Linux */
'Fira Sans', /* Firefox OS */
'Droid Sans', /* Старый Android */
'Helvetica Neue', /* Старый macOS/iOS */
sans-serif; /* Запасной системный шрифт */
}
GitHub использует именно этот стек. Medium перешёл на него несколько лет назад. Для корпоративных сайтов, блогов, SaaS-продуктов — отличное решение. Для брендовых сайтов, где шрифт — часть идентичности — не подходит.
Грубо говоря: если ваш дизайнер не сказал "этот шрифт — часть нашего бренда" — рассмотрите системные шрифты всерьёз. Это даст моментальный прирост PageSpeed и полностью уберёт проблему с загрузкой шрифтов. Такой подход отлично работает в связке с общей оптимизацией производительности — подробнее об этом в статье про Google PageSpeed Insights 2026.
Чек-лист оптимизации шрифтов
По итогам всего вышесказанного — конкретный список действий. Прохожусь по нему на каждом новом проекте.
- Аудит текущих шрифтов. DevTools → Network → Font. Считаем количество файлов, суммарный вес, время загрузки.
- Убираем лишние начертания. Используем только те, которые реально применяются в CSS. Проверяем через поиск в коде: grep -r "font-weight" ваш-css.
- Переходим на самохостирование. Скачиваем шрифты через google-webfonts-helper, кладём на свой сервер.
- Конвертируем в WOFF2. Только WOFF2 + WOFF, без TTF.
- Делаем subsetting. Убираем неиспользуемые языки и символы через pyftsubset.
- Добавляем font-display: swap. Или optional для менее критичных шрифтов.
- Настраиваем preload для 1–2 критических шрифтов в <head>.
- Настраиваем кэширование на сервере. max-age=31536000, immutable.
- Рассматриваем variable fonts, если используем 3+ начертания одного шрифта.
- Проверяем результат в Lighthouse и PageSpeed Insights.
На практике пункты 3–6 дают наибольший эффект. У меня был клиент — небольшой интернет-магазин на Laravel, PHP 8.2, MySQL 8.0. После полной оптимизации шрифтов по этому чек-листу FCP (First Contentful Paint) упал с 2.8 секунды до 1.1 секунды. PageSpeed на мобильных — с 58 до 84 баллов. Без каких-либо других изменений на сайте.
Если нужна помощь с оптимизацией конкретного сайта — это входит в доработку сайта. Аудит делаю бесплатно, чтобы понять объём работ.
Шрифты — это не скучная деталь. Это один из самых недооценённых рычагов для улучшения скорости. Потратьте день на правильную настройку, и результат увидите сразу в Lighthouse — и, что важнее, в поведении реальных пользователей на сайте.
Хотите ускорить загрузку шрифтов на вашем сайте?
Наши специалисты проведут аудит и настроят оптимальную загрузку шрифтов, чтобы ваш сайт работал быстрее и получал высокие оценки Core Web Vitals.