Кэширование веб-шрифтов: заголовки браузера и CDN

Кэширование веб-шрифтов ускоряет повторное открытие страниц, уменьшает сетевой трафик и снижает риск задержки при отображении текста. Для этого сервер отправляет корректные Cache-Control, ETag и Last-Modified, CDN хранит неизменяемые файлы на периферийных узлах, а сайт использует версионирование ресурсов и подходящий font-display. Ниже — практическая схема настройки.
Зачем кэшировать веб-шрифты на сайте
Веб-шрифт обычно загружается как отдельный ресурс после запроса HTML и таблиц стилей. Если браузер уже сохранил файл, повторное посещение страницы может обойтись без новой передачи данных: ресурс берётся из локального кэша или проверяется коротким запросом. Это ускоряет повторные просмотры, особенно на мобильных сетях, где задержка важнее размера отдельного файла.
Кэширование не делает первый визит мгновенным само по себе. На начальную скорость влияют формат WOFF2, число начертаний, размер подмножества символов, порядок загрузки CSS и выбор font-display. Однако после первой загрузки долгий срок хранения позволяет не скачивать тот же шрифт заново. Поэтому эффективная стратегия сочетает оптимизацию файла, правильные HTTP-заголовки и предсказуемое обновление версий.
Как браузер решает, загружать ли шрифт снова
Браузер получает HTTP-ответ с правилами хранения ресурса и записывает его в кэш вместе с временем загрузки, адресом и служебными метаданными. Если срок действия ещё не закончился, браузер использует сохранённый файл без обращения к серверу. Когда ресурс стал устаревшим, браузер может отправить условный запрос и попросить сервер подтвердить, что версия не изменилась.
На поведение влияют прежде всего Cache-Control и связанные с ним директивы. max-age задаёт период свежести в секундах, public разрешает хранение общедоступного ответа промежуточными кэшами, а s-maxage предназначен для общих кэшей, включая CDN. Важное правило: заголовки определяют не только скорость, но и то, насколько быстро пользователи увидят исправленную версию шрифта.
Cache-Control: главный заголовок для шрифта
Для файла, имя которого меняется при каждом обновлении, подходит долгий срок хранения: Cache-Control: public, max-age=31536000, immutable. Директива immutable сообщает браузеру, что в течение срока свежести ресурс не нужно лишний раз перепроверять. Такой вариант безопасен только при настоящем версионировании: если старый URL перезаписывается новым содержимым, браузер продолжит использовать устаревший файл.
Для часто заменяемого файла используют более короткий max-age или стратегию условной проверки. Значение no-cache не означает полный запрет хранения: оно разрешает сохранить ответ, но требует подтвердить его актуальность перед повторным использованием. Директива no-store, напротив, запрещает хранение и для веб-шрифтов обычно не нужна, если ресурс не содержит персональных или конфиденциальных данных.
ETag и Last-Modified для повторной проверки
ETag — идентификатор конкретного представления файла, а Last-Modified — дата его последнего изменения. При устаревшем ответе браузер отправляет If-None-Match или If-Modified-Since. Если файл не изменился, сервер отвечает 304 Not Modified без повторной передачи содержимого. Это экономит трафик, но всё равно требует сетевого обмена, поэтому для неизменяемых версий предпочтительнее долгий кэш с immutable.
Как настроить CDN для веб-шрифтов
CDN кэширует статические файлы на распределённых узлах и отдаёт их пользователю с ближайшей доступной точки. Для шрифтов это особенно полезно при посещениях из разных регионов и при большом числе повторных запросов. CDN должен корректно уважать заголовки исходного сервера, поддерживать HTTPS, передавать правильный Content-Type и не смешивать в одном кэше ответы для разных политик доступа.
Оптимальная схема обычно выглядит так: приложение или объектное хранилище публикует версионированные WOFF2-файлы, CDN получает их при первом запросе и хранит до окончания TTL, а браузеры получают тот же срок хранения. Для срочного удаления ошибочного файла нужна операция purge или invalidation. Но постоянная очистка кэша после каждого релиза снижает пользу CDN, поэтому лучше выпускать новую версию под новым URL.
Разделяйте кэш браузера и кэш CDN
Директива max-age управляет свежестью в браузере, а s-maxage может отдельно задавать срок для CDN. Например, публичный шрифт можно хранить у пользователя 30 дней, а на edge-узле — 7 дней, если обновление должно быстрее доходить до CDN. Для стабильных версий допустим одинаковый длительный TTL на обоих уровнях. Проверяйте фактические заголовки через вкладку Network, а не только конфигурацию панели CDN.
Учитывайте URL, query-параметры и очистку
CDN формирует ключ кэша из URL и, в зависимости от настроек, может учитывать query-параметры, заголовки и cookies. Если одна и та же гарнитура доступна по множеству адресов вроде font.woff2?v=1 и font.woff2?v=2, на edge-узлах появятся отдельные записи. Для статических шрифтов удобнее использовать понятное имя с версией в пути или имени файла и исключить ненужные cookies из запроса.
Версионирование файлов: безопасное обновление шрифта
Долгий кэш работает надёжно, когда URL однозначно связан с содержимым. Можно выпускать файлы с хешем, например inter-cyrillic.a1b2c3.woff2, или менять номер версии в имени: brand-font-v3.woff2. После публикации новой гарнитуры CSS должен ссылаться на новый адрес. Старые файлы можно некоторое время сохранять, чтобы уже открытые страницы не получили ошибку после обновления.
Версионирование решает проблему инвалидации без массового сброса кэша. Если файл изменился, но URL остался прежним, часть пользователей может видеть старое начертание, а часть — новое. Если изменился CSS, но не изменился файл шрифта, достаточно обновить URL таблицы стилей или её заголовки. Важно синхронно публиковать CSS и связанные ресурсы, чтобы браузер не получил ссылку на ещё недоступный файл.
Особенности кэширования WOFF2 и разных начертаний
WOFF2 обычно является предпочтительным форматом для современных браузеров благодаря эффективному сжатию. Не стоит подключать всю гарнитуру, если странице нужны только кириллица и два начертания. Разделение по диапазонам Unicode и ограничение набора символов уменьшают первый сетевой запрос, а кэширование сохраняет каждый небольшой ресурс для следующих посещений. При этом чрезмерное дробление увеличивает число запросов и усложняет контроль версий.
Каждое начертание следует описывать отдельным правилом @font-face с корректными font-family, font-style, font-weight и src. Если браузер не может сопоставить запрошенный вес с доступным файлом, он может использовать синтетическое начертание или загрузить другой ресурс. Это создаёт иллюзию проблемы кэша, хотя причина находится в CSS. Проверяйте итоговый шрифт в computed styles и сетевых запросах.
CORS и MIME-типы не менее важны, чем TTL
Если шрифт обслуживается с отдельного домена или CDN, сервер должен разрешать необходимое междоменное использование через Access-Control-Allow-Origin. При ошибке CORS браузер может скачать файл, но заблокировать его применение. Для WOFF2 также нужен правильный Content-Type, обычно font/woff2. Неверный MIME-тип, редирект с HTTPS на HTTP или отсутствие поддержки HTTPS делают настройку кэша бесполезной.
Preload и font-display: ускоряйте критический текст осторожно
Preload уместен для одного или нескольких действительно критичных файлов, без которых основной текст выглядит неправильно. Для него нужно указать ресурс как font и применить crossorigin, если файл загружается с другого происхождения. Если предварительно загружать все веса и языковые подмножества, браузер получит лишние запросы. font-display: swap позволяет показать резервный шрифт, пока веб-шрифт загружается.
Практический сценарий настройки для сайта
Представим сайт с кириллическим и латинским подмножествами одной гарнитуры, обычным и полужирным начертаниями. Для каждого WOFF2 создаются уникальные имена с хешем содержимого. Сервер отправляет public, max-age=31536000, immutable, CDN повторяет этот TTL, а HTML и CSS получают отдельные правила обновления. При новом релизе меняются ссылки в CSS, но старые шрифты не перезаписываются.
После публикации откройте страницу в чистом окне браузера и проверьте первый запрос: статус должен быть успешным, Content-Type — соответствовать формату, а в ответе должны присутствовать ожидаемые Cache-Control и CORS-заголовки. Затем обновите страницу и изучите колонку Size или статус кэша. Повторный запрос может отсутствовать, быть обслужен из memory cache или disk cache — конкретное отображение зависит от браузера.
Частые ошибки при настройке кэша шрифтов
- Перезаписывать файл под прежним URL и одновременно задавать ему годовой TTL.
- Использовать no-store для всех статических шрифтов без требования безопасности.
- Забывать про CORS при размещении файлов на CDN или отдельном поддомене.
- Подключать несколько одинаковых начертаний с разными font-family и непредсказуемым сопоставлением.
- Предварительно загружать все файлы гарнитуры, включая редко используемые веса и языки.
- Проверять только заголовки исходного сервера и не учитывать правила CDN.
- Очищать весь CDN-кэш после каждого изменения вместо выпуска новой версии ресурса.
Особенно опасна комбинация перезаписи файла и immutable: браузер формально выполняет настройку правильно и долго использует старые байты. Быстрый способ исправления — вернуть прежнее содержимое или выпустить новый URL, а затем обновить CSS. Если проблема наблюдается только у части аудитории, сравните заголовки origin, CDN и браузера, а также проверьте, не влияет ли сервис-воркер.
Чеклист перед публикацией
- Сохраните шрифты в WOFF2 и оставьте только нужные диапазоны символов и начертания.
- Присвойте каждому файлу уникальный URL, связанный с его версией или хешем.
- Задайте Cache-Control с подходящим max-age; immutable используйте только для неизменяемых URL.
- Настройте s-maxage и правила кэширования CDN, если они должны отличаться от браузерных.
- Проверьте Content-Type, HTTPS, CORS и отсутствие неожиданных редиректов.
- Сопоставьте font-family, font-style, font-weight и порядок источников в @font-face.
- Проверьте первый и повторный визит в DevTools на мобильном и десктопном профиле.
- Подготовьте процедуру purge для аварийного удаления ошибочной версии.
Часто задаваемые вопросы
Какой срок кэширования выбрать для веб-шрифтов?
Для версионированных статических файлов обычно выбирают длительный срок хранения, например год, и добавляют immutable. Если URL нельзя менять при обновлении, используйте более короткий max-age и условную проверку через ETag или Last-Modified. Главное — не перезаписывать содержимое ресурса под адресом, который считается неизменяемым.
Нужно ли кэшировать шрифты на CDN?
Да, CDN полезен для публичных статических шрифтов, особенно если сайт обслуживает пользователей из разных регионов. Он снижает расстояние между клиентом и ресурсом и уменьшает нагрузку на исходный сервер. Перед подключением проверьте поддержку HTTPS, CORS, корректный MIME-тип, правила cache key и возможность очистки ошибочной версии.
Чем ETag отличается от Cache-Control?
Cache-Control определяет, сколько времени ответ считается свежим и можно ли хранить его в промежуточных кэшах. ETag идентифицирует конкретную версию содержимого и помогает проверить её актуальность после истечения срока свежести. Эти механизмы дополняют друг друга, но ETag не заменяет долгий кэш для неизменяемых версионированных файлов.
Почему обновлённый шрифт не виден пользователям?
Чаще всего файл был перезаписан под прежним URL, а браузер или CDN ещё считают его свежим. Также причиной могут быть отдельный кэш CSS, сервис-воркер или неочищенная запись на edge-узле. Выпустите новый URL для файла, обновите ссылку в CSS и проверьте цепочку ответов на исходном сервере, CDN и клиенте.
Можно ли использовать query-параметр для версии шрифта?
Да, адрес вида font.woff2?v=2 может использоваться для версионирования, если CDN и сервер учитывают параметр в ключе кэша. Однако отдельная версия в имени или пути часто проще для диагностики и настройки. Не добавляйте случайные параметры, иначе одинаковый файл будет храниться в большом числе независимых кэш-записей.
Зачем нужен font-display: swap при кэшировании?
font-display: swap разрешает временно показать текст системным или резервным шрифтом, пока веб-шрифт загружается. Кэширование ускоряет последующие показы, но не устраняет задержку первого визита. Поэтому swap помогает сохранить доступность и видимость контента, а оптимизированный WOFF2, preload критичного файла и небольшое число начертаний сокращают время перехода к основному шрифту.
Как проверить, что шрифт взят из кэша?
Откройте инструменты разработчика, перейдите во вкладку Network и включите отображение заголовков и размера ответа. При повторной загрузке браузер может показать memory cache, disk cache или отсутствие нового сетевого запроса. Для CDN дополнительно изучите его диагностический заголовок попадания в кэш, если провайдер его предоставляет.
Вывод: кэш должен быть быстрым и предсказуемым
Надёжная схема кэширования веб-шрифтов строится на трёх принципах: лёгкие WOFF2-файлы, уникальные версионированные URL и согласованные правила браузера, CDN и исходного сервера. Для неизменяемых ресурсов подходит долгий TTL с immutable, а для заменяемых — короткая свежесть и проверка через ETag или Last-Modified. Всегда подтверждайте результат реальными сетевыми ответами.
Если для сайта нужен собственный шрифт, создайте его на fontgenerator.ru и подготовьте веб-версии для быстрой загрузки. После этого подключите начертания, настройте кэширование и проверьте отображение на реальных устройствах — так типографика будет одновременно выразительной и производительной.