- Home »

CSS @font-face — как использовать пользовательские шрифты на сайте
Знаете, в нашей работе серверного админа часто приходится решать, казалось бы, простые задачи, которые на деле оказываются не такими уж тривиальными. Вот взять хотя бы кастомные шрифты на сайте — казалось бы, что тут сложного? А на практике оказывается, что неправильно настроенный @font-face может превратить ваш сайт в тормозящее чудище, которое грузится 10 секунд и съедает половину трафика пользователей. Особенно это критично, когда вы управляете несколькими серверами и хостите десятки проектов.
Сегодня разберём, как правильно использовать CSS @font-face, чтобы ваши кастомные шрифты не только красиво выглядели, но и не убивали производительность сервера. Покажу на реальных примерах, как оптимизировать загрузку, настроить кеширование и избежать типичных граблей, на которые наступают 90% разработчиков.
Как работает @font-face под капотом
Начнём с основ. @font-face — это CSS-правило, которое позволяет браузеру загружать шрифты с сервера вместо использования системных. Звучит просто, но дьявол кроется в деталях.
Когда браузер встречает @font-face, он:
- Парсит CSS и находит объявление шрифта
- Определяет, нужен ли этот шрифт для рендеринга страницы
- Делает HTTP-запрос к серверу за файлом шрифта
- Загружает и применяет шрифт к тексту
Проблема в том, что этот процесс может занимать несколько секунд, особенно если шрифт тяжёлый или сервер медленный. А пользователи в это время видят либо системный шрифт, либо вообще пустое место (привет, FOIT!).
Базовая настройка @font-face
Классическое объявление выглядит так:
@font-face {
font-family: 'MyCustomFont';
src: url('/fonts/mycustomfont.woff2') format('woff2'),
url('/fonts/mycustomfont.woff') format('woff'),
url('/fonts/mycustomfont.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
Но это только верхушка айсберга. Давайте разберём каждый параметр:
- font-family — имя шрифта, которое будете использовать в CSS
- src — пути к файлам шрифтов в порядке приоритета
- font-weight/font-style — стиль и насыщенность шрифта
- font-display — как браузер должен вести себя во время загрузки
Пошаговая настройка с оптимизацией
Вот как я настраиваю шрифты на продакшн-серверах:
Шаг 1: Подготовка файлов
Сначала конвертируем шрифты в современные форматы. Используем утилиту fonttools:
# Устанавливаем fonttools
pip install fonttools brotli
# Конвертируем TTF в WOFF2
fonttools ttLib.woff2 compress input.ttf
# Или используем онлайн-конвертер для быстрого результата
# Но лучше автоматизировать этот процесс
Шаг 2: Структура каталогов
/var/www/site/
├── fonts/
│ ├── roboto-regular.woff2
│ ├── roboto-regular.woff
│ ├── roboto-bold.woff2
│ └── roboto-bold.woff
└── css/
└── fonts.css
Шаг 3: Правильное объявление CSS
/* Preload критически важные шрифты в HTML */
/* */
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-regular.woff2') format('woff2'),
url('/fonts/roboto-regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto-bold.woff2') format('woff2'),
url('/fonts/roboto-bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
Шаг 4: Настройка сервера
Для Apache (.htaccess):
# Включаем сжатие для шрифтов
AddType application/font-woff2 .woff2
AddOutputFilterByType DEFLATE application/font-woff2
# Настраиваем кеширование
ExpiresActive on
ExpiresByType application/font-woff2 "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
# CORS для шрифтов
Header set Access-Control-Allow-Origin "*"
Для Nginx:
location ~* \.(woff2?|ttf|otf)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin "*";
# Предварительное сжатие
gzip_static on;
gzip_types
application/font-woff2
font/woff2;
}
Сравнение форматов шрифтов
Формат | Размер | Поддержка | Когда использовать |
---|---|---|---|
WOFF2 | ~30% меньше TTF | IE11+, все современные | Основной формат для продакшена |
WOFF | ~20% меньше TTF | IE9+ | Fallback для старых браузеров |
TTF | Базовый размер | Все браузеры | Только для крайних случаев |
EOT | Больше TTF | IE6-8 | Устаревший, не используем |
Продвинутые техники оптимизации
Subset fonts — загружаем только нужные символы:
# Создаём subset только с латинскими символами
pyftsubset font.ttf --output-file=font-latin.woff2 --flavor=woff2 --layout-features='*' --unicodes=U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD
# Или только кириллица
pyftsubset font.ttf --output-file=font-cyrillic.woff2 --flavor=woff2 --layout-features='*' --unicodes=U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116
Variable fonts — один файл вместо множества начертаний:
@font-face {
font-family: 'InterVariable';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
/* Использование */
.text {
font-family: 'InterVariable', sans-serif;
font-weight: 350; /* Любое значение в диапазоне */
}
Автоматизация и мониторинг
Создаём скрипт для автоматической оптимизации шрифтов:
#!/bin/bash
# optimize-fonts.sh
FONTS_DIR="/var/www/fonts"
TEMP_DIR="/tmp/font-processing"
mkdir -p $TEMP_DIR
for font in $FONTS_DIR/*.ttf; do
filename=$(basename "$font" .ttf)
# Конвертируем в WOFF2
fonttools ttLib.woff2 compress "$font" -o "$FONTS_DIR/${filename}.woff2"
# Создаём subset для латиницы
pyftsubset "$font" --output-file="$FONTS_DIR/${filename}-latin.woff2" \
--flavor=woff2 --layout-features='*' \
--unicodes=U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD
echo "Processed: $filename"
done
# Проверяем размеры
du -h $FONTS_DIR/*.woff2
Мониторинг производительности через скрипт:
#!/bin/bash
# check-font-performance.sh
SITE_URL="https://your-site.com"
FONT_PATH="/fonts"
# Проверяем время загрузки шрифтов
curl -w "@curl-format.txt" -o /dev/null -s "$SITE_URL$FONT_PATH/roboto-regular.woff2"
# Проверяем размеры шрифтов
find /var/www/fonts -name "*.woff2" -exec ls -lh {} \; | awk '{print $5 " " $9}'
Типичные проблемы и их решения
FOIT (Flash of Invisible Text) — пользователи видят пустое место во время загрузки шрифта:
/* Решение: используем font-display: swap */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
font-display: swap; /* Показываем fallback до загрузки */
}
Медленная загрузка — шрифты грузятся слишком долго:
/* Preload критически важные шрифты в HTML */
/* Используем local() для проверки системных шрифтов */
@font-face {
font-family: 'MyFont';
src: local('Arial'),
url('/fonts/font.woff2') format('woff2');
}
CORS ошибки — шрифты не загружаются с CDN:
# Настраиваем CORS в Nginx
location ~* \.(woff2?|ttf|otf)$ {
add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization";
}
Интересные факты и нестандартные применения
Вот несколько фишек, которые мало кто знает:
- Unicode-range — можно загружать разные шрифты для разных языков автоматически
- Font-feature-settings — активируем лигатуры и другие OpenType-фичи
- Font-variation-settings — тонкая настройка variable fonts
@font-face {
font-family: 'MultiLang';
src: url('/fonts/latin.woff2') format('woff2');
unicode-range: U+0000-00FF; /* Только латиница */
}
@font-face {
font-family: 'MultiLang';
src: url('/fonts/cyrillic.woff2') format('woff2');
unicode-range: U+0400-04FF; /* Только кириллица */
}
/* Использование OpenType-фич */
.code {
font-family: 'FiraCode', monospace;
font-feature-settings: "liga" 1, "calt" 1; /* Лигатуры */
}
Интеграция с системами сборки
Для больших проектов удобно автоматизировать процесс через webpack:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(woff2?|ttf|otf)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'fonts/',
publicPath: '/fonts/',
}
}
}
]
}
};
Производительность и метрики
Для мониторинга производительности шрифтов использую такие метрики:
- FCP (First Contentful Paint) — когда появляется первый текст
- LCP (Largest Contentful Paint) — когда загружается основной контент
- CLS (Cumulative Layout Shift) — как сильно “прыгает” макет
Мониторим через Google PageSpeed Insights API:
#!/bin/bash
# pagespeed-check.sh
API_KEY="your-api-key"
URL="https://your-site.com"
curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=$URL&key=$API_KEY" | \
jq '.lighthouseResult.audits["font-display"].score'
Альтернативные решения
Кроме @font-face есть несколько альтернативных подходов:
- Google Fonts API — быстро, но зависимость от внешнего сервиса
- System font stack — максимальная производительность, но ограниченный выбор
- Font loading API — JavaScript-контроль загрузки шрифтов
Для высоконагруженных проектов рекомендую комбинированный подход:
/* Сначала system fonts для быстрого рендеринга */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Затем асинхронно загружаем кастомные */
.fonts-loaded body {
font-family: 'CustomFont', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
Заключение и рекомендации
Правильная настройка @font-face — это не только про красивый дизайн, но и про производительность всего сайта. Особенно это критично, когда вы управляете множеством проектов на VPS или выделенных серверах.
Мои главные рекомендации:
- Используйте WOFF2 как основной формат
- Всегда добавляйте font-display: swap
- Настройте правильное кеширование на сервере
- Мониторьте производительность через метрики
- Автоматизируйте процесс оптимизации
И помните: лучший шрифт — это тот, который пользователь не замечает. Если ваши кастомные шрифты тормозят сайт, лучше откажитесь от них в пользу системных. Производительность всегда важнее красоты.
P.S. Не забывайте регулярно проверять актуальность форматов и поддержку браузеров. Веб-технологии развиваются быстро, и то, что работало год назад, может быть уже неоптимально сегодня.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.