Критический CSS и отложенная загрузка: чек-лист перед продом
Что проверить в критическом CSS и стратегии отложенной загрузки стилей, прежде чем катить сборку в прод: от FOUC до кеша CDN и мобильного вьюпорта.

Вы вынесли above-the-fold стили в <style> в <head>, остальной CSS грузите отложенно, LCP на демо-стенде упал с 3,1 до 1,6 секунды. А на проде через неделю приходит жалоба: на первых 200 мс страница дёргается, шрифт прыгает, кнопка съезжает. Это не мистика — это набор типичных дыр в реализации критического CSS, которые не видны на быстром ноутбуке с горячим кешем. Ниже — чек-лист того, что проверить до релиза, и цена каждого пропущенного пункта.
Материал — про приёмы и подводные камни при внедрении, а не про то, как в принципе работает рендеринг. Инвалидацию кеша критического CSS при деплое затрагиваю одним пунктом, но подробно её не разворачиваю.
Что вообще проверяем
Критический CSS (critical CSS) — это минимальный набор правил, нужный для отрисовки той части страницы, которую пользователь видит без прокрутки. Он инлайнится прямо в HTML, чтобы браузеру не пришлось ждать сетевого запроса к внешнему файлу перед первой отрисовкой. Остальной CSS подключается отложенно и не блокирует рендеринг.
Проблема в том, что «работает у меня» и «работает у пользователя на 4G с холодным кешем и вьюпортом 360×640» — разные состояния. Чек-лист ниже проверяет именно второе.
Базовый паттерн отложенной загрузки
Самый распространённый способ загрузить некритичный CSS без блокировки рендеринга — трюк с media="print", который переключается на all после загрузки файла. Он работает в актуальных версиях Chrome, Firefox и Safari:
<!-- критический CSS инлайном -->
<style>
/* только то, что видно без прокрутки */
body { margin: 0; font-family: system-ui, sans-serif; }
.header { height: 64px; }
/* ... */
</style>
<!-- остальной CSS грузим не блокируя рендеринг -->
<link rel="stylesheet" href="/static/main.css"
media="print" onload="this.media='all'">
<noscript>
<link rel="stylesheet" href="/static/main.css">
</noscript>
Атрибут media="print" говорит браузеру, что стили нужны только для печати, поэтому файл скачивается с низким приоритетом и не блокирует первую отрисовку. После загрузки onload переключает media на all, и стили применяются. Блок <noscript> обязателен: без JS onload не сработает, и страница останется без стилей.
Чек-лист перед продакшеном
- FOUC на медленной сети. Откройте DevTools → Network → троттлинг «Slow 4G», очистите кеш и перезагрузите. Если после первой отрисовки контент прыгает, когда подгрузился основной CSS, — в критический набор попало не всё, что видно в первом экране, либо туда, наоборот, попал лишний CSS для нижней части страницы, раздувший
<head>. - Размер инлайн-блока. Критический CSS уходит в HTML каждой страницы и не кешируется отдельно. Если он весит 40–50 КБ, вы утяжеляете каждый ответ и теряете часть выигрыша. Ориентир для мобильного above-the-fold — единицы килобайт, редко больше 14 КБ (объём, который влезает в первый пакет TCP при медленном старте). Точную цифру решайте по своему макету, но следите, чтобы блок не рос бесконтрольно.
- Правильный вьюпорт при генерации. Инструменты вроде
criticalилиpenthouseвырезают критический CSS под заданную ширину и высоту окна. Если сгенерировали под десктоп 1300×900, а основная аудитория на мобильных 360×640 — в критический набор не попадут стили мобильного меню и мобильной сетки, и на телефоне будет FOUC. Генерируйте под тот вьюпорт, что доминирует в аналитике, либо под несколько. - Разные шаблоны — разный критический CSS. Главная, карточка товара и статья блога имеют разный первый экран. Один инлайн-блок на все страницы либо не покрывает часть, либо тащит лишнее. Генерируйте критический CSS по типам шаблонов, а не один на весь сайт.
- Шрифты и CLS. Критический CSS ускоряет отрисовку, но если веб-шрифт грузится отдельно и подменяет системный, текст перекомпоновывается — растёт Cumulative Layout Shift. Проверьте
font-displayи зарезервируйте место под шрифт (size-adjust, метрики fallback-шрифта). Это отдельная тема, но её нельзя игнорировать при замере CLS. - Работа без JS. Уберите
<noscript>и отключите JavaScript в браузере. Если основной CSS не подключился — вы уронили страницу для части пользователей и поисковых роботов, которые могут не исполнятьonload. Блок<noscript>должен присутствовать всегда. - Preload для критичных ресурсов. Отложенный
<link>сmedia="print"не форсирует раннюю загрузку. Если основной CSS большой, а страница длинная, добавьте<link rel="preload" as="style">для него, чтобы браузер начал качать файл раньше. Не путайте preload и отложенную загрузку — это разные механизмы, применяйте осознанно. - Инвалидация при деплое. Критический CSS вшит в HTML. Если вы изменили макет и пересобрали
main.css, но старый инлайн-блок остался в кеше страницы (CDN, серверный кеш шаблонов) — пользователь увидит рассинхрон. Проверьте, что генерация критического CSS встроена в билд и кеш HTML сбрасывается вместе с релизом стилей. - Кеш CDN и Vary. Если вы отдаёте разный критический CSS для мобильных и десктопа на одном URL, убедитесь, что CDN не отдаёт всем одну версию из кеша. Либо разделяйте по URL, либо используйте корректный
Vary, либо генерируйте один набор, покрывающий оба вьюпорта. - Замер после, а не «на глаз». Прогоните Lighthouse в режиме мобильного с троттлингом до и после внедрения. Смотрите не только на общий балл, а на LCP, FCP и CLS отдельно. Улучшение FCP при выросшем CLS — это не улучшение.
Критический CSS часто ускоряет первую отрисовку и одновременно ухудшает CLS: контент появляется быстрее, но потом дёргается под догрузившимися стилями и шрифтами. Мерьте оба показателя, иначе оптимизируете один за счёт другого.
Как проверить, что критический CSS реально полный
Ручной способ, который ловит большинство дыр: в DevTools отключите внешний CSS-файл целиком (например, заблокируйте main.css через Network → Block request URL) и перезагрузите страницу. То, что вы видите, — это и есть результат только инлайн-стилей. Первый экран должен выглядеть корректно: сетка стоит, шрифт на месте, кнопки не разъехались. Всё, что сломалось в верхней части, — пропущено в критическом наборе.
Дальше сравните это с полной версией. Если ниже первого экрана всё без стилей — это нормально, туда критический CSS и не должен доставать.
Частая ошибка: инлайн грузится, а файл — нет
Проверьте в Network, что main.css действительно догрузился и media переключился на all. Если onload не отработал (например, из-за CSP, блокирующего инлайн-обработчики), страница навсегда останется на одном критическом CSS. При строгой Content-Security-Policy инлайн-onload может не выполниться — тогда переключение делают через отдельный скрипт с nonce, а не через атрибут.
Сравнение способов подключения некритичного CSS
| Способ | Блокирует рендеринг | Работает без JS | Риск |
|---|---|---|---|
Обычный <link rel="stylesheet"> | Да | Да | Медленный первый рендер |
media="print" + onload | Нет | Только с <noscript> | CSP может блокировать onload |
rel="preload" as="style" + переключение | Нет | Требует fallback | Сложнее, легко ошибиться в приоритетах |
Что делать дальше
Встройте генерацию критического CSS в CI-сборку, чтобы он пересчитывался при каждом изменении стилей, а не жил захардкоженным в шаблоне. После релиза следите в реальных данных: подключите сбор Core Web Vitals с живых пользователей (RUM), а не полагайтесь только на лабораторный Lighthouse — лабораторный замер не покажет FOUC у пользователя с медленным устройством и холодным кешем. Ключевые метрики для наблюдения — LCP, FCP и CLS в разрезе мобильных и десктопа отдельно.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: web.dev — Extract critical CSS, MDN — CSS and JavaScript animation performance / render blocking
Частые вопросы
А если у меня статический сайт без сборки — как генерировать критический CSS?
Трюк с media=print не сработал — стили так и не применились. Что проверить?
Насколько большим может быть инлайн-блок критического CSS?
Грозит ли критический CSS проблемами с SEO?
Нужен ли критический CSS, если сайт и так грузится быстро?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.