Оптимизация загрузки шрифтов на сайте: руководство 2026

Шрифты — одна из тех вещей, на которые обычно не обращают внимания при оптимизации, а потом удивляются, почему 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.

💡
Конвертация шрифтов: Для конвертации TTF/OTF в WOFF2 я использую утилиту 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. Я пользуюсь им постоянно.

⚠️
Внимание: Если вы переносите шрифты на свой сервер, убедитесь, что лицензия шрифта позволяет самохостирование. Google Fonts все распространяются под открытыми лицензиями (OFL, Apache), но коммерческие шрифты могут иметь ограничения на количество серверов или доменов.

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.

ℹ️
Инструмент для диагностики: Используйте Google Fonts Checker или просто откройте DevTools → Network → фильтр "font". Посмотрите, сколько шрифтовых файлов загружается, их размер и время загрузки. Если суммарный вес шрифтов больше 150 КБ — есть что оптимизировать.

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.

Чек-лист оптимизации шрифтов

По итогам всего вышесказанного — конкретный список действий. Прохожусь по нему на каждом новом проекте.

  1. Аудит текущих шрифтов. DevTools → Network → Font. Считаем количество файлов, суммарный вес, время загрузки.
  2. Убираем лишние начертания. Используем только те, которые реально применяются в CSS. Проверяем через поиск в коде: grep -r "font-weight" ваш-css.
  3. Переходим на самохостирование. Скачиваем шрифты через google-webfonts-helper, кладём на свой сервер.
  4. Конвертируем в WOFF2. Только WOFF2 + WOFF, без TTF.
  5. Делаем subsetting. Убираем неиспользуемые языки и символы через pyftsubset.
  6. Добавляем font-display: swap. Или optional для менее критичных шрифтов.
  7. Настраиваем preload для 1–2 критических шрифтов в <head>.
  8. Настраиваем кэширование на сервере. max-age=31536000, immutable.
  9. Рассматриваем variable fonts, если используем 3+ начертания одного шрифта.
  10. Проверяем результат в 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.

П
Павел
Веб-разработчик · 10+ лет опыта · Bitrix, WordPress, Laravel

Читайте также

Выбор CMS для интернет-магазина: сравнение Защита XML-RPC и wp-login.php: полное руководство 2026 Настройка CORS-заголовков на сайте: полное руководство 2026