Оптимизация Cumulative Layout Shift при загрузке пользовательских шрифтов

Если вы хоть раз открывали тяжелый лендинг с медленным соединением, вы наверняка сталкивались с раздражающим эффектом: текст сначала появляется одним шрифтом (обычно стандартным Arial или Times New Roman), а через секунду резко меняет начертание, при этом весь контент страницы «прыгает» вверх или вниз. В метриках Core Web Vitals это называется Cumulative Layout Shift (CLS).
Для пользователя это выглядит как дешевый интерфейс, для SEO-специалиста — как падение позиций в выдаче Google, а для разработчика — как необходимость глубоко копаться в механизмах рендеринга браузера. Давайте разберем, почему это происходит и как приручить шрифты так, чтобы верстка стояла «как влитая».
Анатомия проблемы: FOIT и FOUT
Прежде чем лечить, нужно понять диагноз. Браузер обрабатывает шрифты по определенным сценариям, которые определяют визуальный опыт пользователя.
- FOIT (Flash of Invisible Text) — «вспышка невидимого текста». Браузер скрывает текст до тех пор, пока пользовательский шрифт не будет полностью загружен. В итоге пользователь видит пустой экран или пустые блоки там, где должен быть заголовок. Это ужасно с точки зрения UX и LCP (Largest Contentful Paint).
- FOUT (Flash of Unstyled Text) — «вспышка неотстилизованного текста». Браузер сразу показывает текст системным шрифтом (fallback), а после загрузки кастомного файла заменяет его. Именно здесь рождается основной вклад в CLS, так как разные шрифты имеют разную ширину глифов, высоту строки и межбуквенные интервалы.
Когда системный шрифт Arial заменяется на дизайнерский Montserrat, заголовок может занять на 10-20 пикселей больше по высоте. Если этот заголовок находится в верхней части страницы, он «толкает» весь остальной контент вниз. Это и есть Layout Shift.
Стратегия №1: Правильное управление font-display
Самый простой и первый шаг — использование свойства font-display в директиве @font-face. Оно говорит браузеру, как себя вести в период ожидания.
-
auto— стандартное поведение браузера (обычно FOIT).
-
block— жесткий FOIT. Текст скрыт до 3 секунд. Не рекомендуется для критического контента.
-
swap— принудительный FOUT. Текст показывается сразу системным шрифтом, а затем меняется. Это лучший вариант для доступности, но именно он создает риск CLS.
-
fallbackиoptional— более мягкие варианты.optionalвообще может отказаться загружать шрифт, если сеть слишком медленная, оставив системный шрифт на всю сессию. Это идеальный вариант для второстепенных текстов.
Вердикт: Для основных заголовков используйте swap, но сочетайте это с методами минимизации сдвига, описанными ниже.
Стратегия №2: Прелоадинг критических ресурсов
Браузер узнает о необходимости загрузки шрифта довольно поздно: сначала парсится HTML, затем CSS, затем браузер понимает, что для конкретного селектора нужен файл .woff2. Чтобы сократить этот путь, используйте <link rel="preload">.
Важные нюансы:
- Атрибут
crossoriginобязателен, даже если шрифт лежит на вашем домене. Без него браузер скачает шрифт дважды. - Не прелоадите всё подряд. Если вы добавите в preload 10 вариантов начертаний (Light, Regular, Bold, Italic и т.д.), вы забьете канал загрузки, и критический CSS или JS будут ждать своей очереди. Прелоадите только 1-2 самых важных файла для первого экрана (Above the Fold).
Стратегия №3: Математический подход к Fallback-шрифтам
Это самая сложная, но и самая эффективная часть. Суть в том, чтобы подобрать системный шрифт, который по геометрии максимально близок к вашему кастомному.
Если ваш основной шрифт — широкий геометрический гротеск, а в качестве fallback стоит узкий serif, скачок будет катастрофическим.
Использование size-adjust и ascent-override
Современный CSS предоставляет инструменты для «подгонки» системного шрифта под размер пользовательского. С помощью свойств в @font-face мы можем создать «виртуальный» fallback-шрифт.
css
@font-face {
font-family: ‘MyCustomFont-Fallback’;
src: local(‘Arial’);
size-adjust: 95%; / Масштабируем системный шрифт, чтобы он совпадал по ширине /
ascent-override: 90%; / Корректируем верхний вынос /
descent-override: 20%; / Корректируем нижний вынос /
line-gap-override: 0%;
}
body {
font-family: ‘MyCustomFont’, ‘MyCustomFont-Fallback’, sans-serif;
}
Как это работает на практике?
Вы берете системный шрифт (например, Arial) и с помощью size-adjust немного сжимаете или расширяете его так, чтобы один и тот же объем текста занимал одинаковое количество пикселей и в Arial, и в вашем основном шрифте. В итоге при смене шрифта буквы меняют форму, но общие границы текстового блока остаются прежними. Контент не прыгает.
Стратегия №4: Оптимизация форматов и веса
Чем быстрее загрузится шрифт, тем меньше вероятность, что пользователь заметит смену.
-
- Только WOFF2. Забудьте про TTF или OTF для веба. WOFF2 имеет самое эффективное сжатие.
-
- Subset-тирование (Подмножества). Зачем грузить весь набор символов (кириллица, латиница, греческий, спецсимволы), если ваш сайт только на русском и английском? Используйте инструменты (например,
pyftsubsetиз пакетаfonttools), чтобы вырезать лишние глифы. Это может уменьшить вес файла с 100 Кб до 30 Кб.
- Subset-тирование (Подмножества). Зачем грузить весь набор символов (кириллица, латиница, греческий, спецсимволы), если ваш сайт только на русском и английском? Используйте инструменты (например,
-
- Локальный хостинг. Загрузка шрифтов с Google Fonts создает лишний DNS-запрос и TLS-handshake. Размещение шрифтов на своем сервере или CDN с HTTP/2 или HTTP/3 значительно ускоряет доставку.
Чек-лист по внедрению (Step-by-Step)
Чтобы систематизировать работу, следуйте этому алгоритму:
-
- Анализ: Откройте Chrome DevTools $\rightarrow$ вкладка Network $\rightarrow$ ограничьте скорость до «Fast 3G». Посмотрите, насколько сильно «прыгает» верстка.
-
- Оптимизация файлов: Конвертируйте всё в
.woff2и сделайте сабсеттинг под нужные языки.
- Оптимизация файлов: Конвертируйте всё в
-
- Приоритезация: Добавьте
<link rel="preload">для основного шрифта первого экрана.
- Приоритезация: Добавьте
-
- Настройка отображения: Установите
font-display: swapдля основных шрифтов иfont-display: optionalдля второстепенных.
- Настройка отображения: Установите
-
- Геометрическая подгонка: Используйте
size-adjustдля создания кастомного fallback-шрифта, чтобы минимизировать разницу в ширине строк.
- Геометрическая подгонка: Используйте
-
- Валидация: Проверьте страницу в Lighthouse или PageSpeed Insights. Значение CLS должно стремиться к 0.
Заключение
Оптимизация CLS при загрузке шрифтов — это не про выбор одного «волшебного» свойства, а про комплексный подход. Использование preload ускоряет доставку, font-display управляет логикой отображения, а size-adjust убирает визуальный сдвиг.
В современном вебе, где скорость загрузки и стабильность интерфейса напрямую влияют на конверсию и SEO, такие детали становятся решающими. Помните: идеальный пользовательский опыт — это когда интерфейс ощущается монолитным и предсказуемым с первой миллисекунды загрузки.

