Как работает @font-face: глубокий технический разбор
От декларации в CSS до рендера на экране — что происходит под капотом
@font-face — правило CSS, которое позволяет загружать шрифты из внешних источников и использовать их в网页-страницах. Это базовый механизм веб-типографики, без которого современный веб был бы привязан к системным шрифтам. Но несмотря на то, что @font-face появился ещё в CSS2 (1998), его внутренности часто остаются за кадром. В этой статье — глубокий разбор: что происходит от декларации в CSS до рендера на экране, какие дескрипторы существуют и что может пойти не так.
Правило @font-face состоит из дескрипторов — пар ключ-значение, которые описывают подключаемый шрифт. Минимальный набор: font-family (имя, под которым шрифт будет доступен в CSS) и src (URL, откуда браузер грузит файл). Без этих двух дескрипторов правило не имеет смысла. Остальные дескрипторы опциональны, но критичны для корректной работы.
Пример минимального @font-face: @font-face { font-family: 'Inter'; src: url('inter.woff2') format('woff2'); }. Этого достаточно, чтобы браузер загрузил файл и сделал шрифт доступным под именем Inter. В реальных проектах правило обычно содержит больше дескрипторов: font-weight, font-style, font-display, unicode-range. Каждый из них выполняет конкретную задачу, и понимание их работы — ключ к предсказуемому рендеру.
src — главный дескриптор, определяет, откуда браузер берёт файл шрифта. Значение состоит из двух частей: url (путь к файлу) и format (подсказка браузеру о формате файла). Подсказка format критична: без неё браузер пытается «угадать» формат по URL или по MIME-типу, что не всегда работает корректно. Современные форматы: woff2 (компрессия Brotli, на 30% меньше woff), woff (компрессия zlib, поддержка во всех браузерах с IE9), truetype/woff (старый формат TTF/OTF), embedded-opentype (легаси для IE).
Чтобы дать браузеру выбор, можно указать несколько форматов в порядке предпочтения. Браузер возьмёт первый, который он понимает. Пример: src: url('inter.woff2') format('woff2'), url('inter.woff') format('woff'), url('inter.ttf') format('truetype');. Современные браузеры возьмут woff2, старые (IE11, Safari 9) — woff или ttf. Это «прогрессивное улучшение»: вы даёте каждому браузеру тот формат, с которым он работает эффективнее.
Для переменных шрифтов есть специальные подсказки формата: format('woff2-variations'), format('woff-variations'). Они говорят браузеру: «это переменный шрифт, поддерживающий оси». Без такой подсказки некоторые браузеры могут не активировать оси корректно. В каталоге FontHub при генерации CSS мы автоматически добавляем корректные подсказки для всех поддерживаемых форматов.
font-display — дескриптор, который контролирует, как браузер рендерит текст во время загрузки шрифта. Без него поведение зависит от браузера: Chrome по умолчанию использует block (3 секунды невидимого текста, потом fallback), Safari — swap (сразу fallback, потом подмена). Эта разница приводит к «миганию шрифта» (FOIT — Flash of Invisible Text) или «миганию стиля» (FOUT — Flash of Unstyled Text), которые раздражают пользователей.
font-display принимает пять значений: auto (по умолчанию, браузер сам решает), block (скрывает текст до 3 секунд, потом fallback, потом подмена), swap (сразу fallback, потом подмена), fallback (100 мс скрытого текста, потом fallback, потом подмена только если шрифт загрузился за 3 секунды), optional (100 мс скрытого текста, потом fallback, подмена только если шрифт уже в кэше).
Для интерфейсных шрифтов рекомендуется swap — пользователь сразу видит текст в fallback-шрифте, а при загрузке основного — подмене. Это даёт мгновенный отклик и «догрузку» шрифта. Для акцентных шрифтов (например, Playfair Display в заголовках) можно использовать block — лучше показать заголовок чуть позже, чем мигать шрифтами. Для критических шрифтов, где мигание недопустимо — optional, который «заранее» определяет, грузить ли шрифт в этом визите.
unicode-range — дескриптор, который позволяет указать, для каких Unicode-диапазонов использовать данный @font-face. Это особенно важно для шрифтов с большим количеством языков: браузер грузит только то подмножество глифов, которое реально используется на странице. Например, если у вас сайт на русском, можно подключить только кириллическое подмножество Inter, без латиницы, что уменьшает размер файла в 2–3 раза.
Пример: @font-face { font-family: 'Inter'; src: url('inter-cyr.woff2') format('woff2'); unicode-range: U+0400-04FF, U+0500-052F; }. Это правило говорит браузеру: «грузи этот файл, только если на странице есть кириллические символы (диапазон U+0400-04FF — это основная кириллица, U+0500-052F — расширенная)». Если на странице нет кириллицы, браузер не будет грузить этот файл вообще.
Для сайтов, где используется и кириллица, и латиница, можно подключить два подмножества Inter отдельными @font-face с разными unicode-range. Браузер возьмёт только нужные. В каталоге FontHub мы автоматически генерируем подмножества для популярных шрифтов: Inter Cyrillic, Inter Latin, Inter Latin Extended. Подключайте только те, которые нужны вашему проекту — это ускорит загрузку на 30–50%.
Самая частая проблема — CORS. Если шрифт грузится с другого домена, сервер должен вернуть заголовок Access-Control-Allow-Origin: * (или конкретный домен). Без этого браузер откажется использовать шрифт из соображений безопасности. Если вы используете CDN (как FontHub), проверьте, что у него настроен CORS — у нас это сделано по умолчанию для всех публичных шрифтов.
Вторая проблема — MIME-тип. Сервер должен отдавать WOFF2 с типом font/woff2, а не application/octet-stream. Без правильного MIME-типа некоторые браузеры откажутся использовать файл. Если вы хостите шрифты сами, проверьте конфигурацию веб-сервера. Если используете CDN FontHub — тип уже настроен правильно.
Третья проблема — порядок дескрипторов в src. Браузер берёт первый формат, который он понимает, поэтому woff2 должен идти первым, потом woff, потом ttf. Если в обратном порядке, браузер может взять ttf, даже если понимает woff2, что приведёт к лишнему трафику. Все эти нюансы — не теоретические, а реальные проблемы, с которыми сталкиваются разработчики. В каталоге FontHub при генерации CSS мы учитываем все эти моменты автоматически.
Ещё один важный аспект: современные браузеры поддерживают prefetch и preload для шрифтов, что радикально ускоряет их загрузку. Тег link rel=preload as=font с указанием type=font/woff2 и crossorigin говорит браузеру: «начни грузить этот шрифт сразу, не дожидаясь парсинга CSS». Это критично для основного шрифта интерфейса — без preload браузер может ждать 200-500 мс, пока распарсит CSS, и только потом начнёт грузить шрифт. С preload — шрифт грузится параллельно с CSS и HTML, экономя 200-500 мс на каждой загрузке страницы. Для secondary-шрифтов (акцентных, не критичных) preload обычно не нужен — они могут «догрузиться» после основной отрисовки, и font-display: swap обеспечит корректный рендер. Не перегружайте preload: если вы укажете 5 шрифтов в preload, браузер будет грузить их все параллельно, что может забить канал и замедлить загрузку критических ресурсов. Рекомендация — preload только основной шрифт интерфейса (один файл WOFF2, минимально необходимое подмножество). В каталоге FontHub при подключении через наш CDN preload генерируется автоматически для критических шрифтов — вам не нужно вручную прописывать теги link.
«@font-face — это не одна строка CSS. Это контракт между браузером, сервером и дизайнером.» — Матиас Биненс
@font-face — мощный инструмент, но его корректная работа требует понимания нюансов. Дескриптор src с правильными подсказками формата, font-display с корректной стратегией рендера, unicode-range для оптимизации кириллицы, правильный MIME-тип и CORS на сервере — все эти элементы вместе дают предсказуемый и быстрый рендер шрифтов. В каталоге FontHub мы автоматически генерируем корректный CSS со всеми дескрипторами, так что вам не нужно разбираться в каждом из них вручную. Но если что-то работает не так — теперь вы знаете, где искать причину.
Понравилась статья?