Критический CSS: как убрать блокировку рендера без плагинов
Что такое render-blocking CSS, как собрать критические стили для первого экрана и подключить остальное асинхронно.
Содержание
- Что происходит с рендером, пока браузер ждёт CSS
- Как понять, что стили реально блокируют
- Сбор критических стилей: инструменты и ручной способ
- Как подключить остаток асинхронно и не поймать прыжок вёрстки
- Шрифты и font-display: сосед по проблеме
- Когда всё это не нужно
- Сравнение подходов
- Чек-лист перед сдачей работы
- Что делать дальше
- Частые вопросы
Критический CSS это те правила, которые нужны для первого экрана. Их вставляют прямо в страницу, остальное подгружают асинхронно. На типовой странице услуги реально используется около 15 процентов правил из подключённого файла, а первая отрисовка ускоряется почти вдвое.
Проверяем сайт в PageSpeed Insights и упираемся в предупреждение «Устраните ресурсы, блокирующие отображение». В списке styles.css, bootstrap.min.css, ещё пара файлов от плагинов. Первая мысль обычно, поставить плагин для критического CSS и забыть. Вторая мысль, если плагин уже стоит и не помог, разобраться руками. Эта статья для тех, кто хочет понять, что вообще происходит с рендером, пока браузер грузит CSS, и собрать критические стили без чёрного ящика от плагина, который иногда ломает вёрстку сильнее, чем чинит скорость.

Что происходит с рендером, пока браузер ждёт CSS
Браузер строит две модели параллельно: DOM из HTML и CSSOM из CSS. Отрисовать хотя бы один пиксель он не может, пока не построены обе. Если CSS-файл подключён в head обычным тегом link без media-атрибута, он считается блокирующим рендер: браузер сначала скачает файл целиком, разберёт его, и только потом покажет первый кадр страницы.
На быстром домашнем Wi-Fi разница незаметна, файл в 60 килобайт грузится за 40-80 миллисекунд. На мобильной сети 3G или на перегруженном 4G та же загрузка легко растягивается на 400-900 миллисекунд, и всё это время пользователь смотрит на белый экран. Для метрики LCP (Largest Contentful Paint) это прямой удар: пока не применены стили, браузер не может корректно отрисовать даже самый крупный видимый элемент, будь то заголовок или картинка на весь экран.
Отдельная деталь: если CSS подключён через @import внутри другого CSS-файла, цепочка запросов удлиняется ещё на один цикл ожидания. Видел сайты, где так подключали три-четыре файла подряд, и суммарная задержка перед первой отрисовкой доходила до полутора секунд только на стилях, без учёта самого HTML и шрифтов.
Как понять, что стили реально блокируют
Не всякий CSS одинаково вреден. Прежде чем что-то чинить, стоит измерить масштаб проблемы, а не гадать.
Первый инструмент, отчёт PageSpeed Insights или Lighthouse. Аудит «Eliminate render-blocking resources» прямо перечисляет файлы и показывает, сколько миллисекунд экономии даст их устранение. Если экономия меньше 100-150 миллисекунд, возиться с критическим CSS обычно не стоит: выигрыш не окупит риск сломать вёрстку.
Второй инструмент, вкладка Coverage в DevTools Chrome. Открывается через Ctrl+Shift+P, ввод «Show Coverage», дальше кнопка перезаписи страницы. Инструмент показывает для каждого CSS-файла долю неиспользуемого кода красной полосой. Если файл на 80-90 процентов красный, значит на странице используется лишь малая часть стилей, а остальное это код для других шаблонов сайта, который зря блокирует первую отрисовку именно здесь.
Практический пример с одного из моих проектов на WordPress: общий styles.css весил 180 килобайт и грузился на каждой странице, хотя на конкретной странице услуги использовалось от силы 15 процентов правил. После выделения критической части и переноса остального в асинхронную загрузку время до первой отрисовки на мобильном тесте сократилось с 1,9 до 1,1 секунды.
Сбор критических стилей: инструменты и ручной способ
Критический CSS это набор правил, которые нужны для корректного отображения того, что видно без прокрутки, обычно область высотой 600-900 пикселей в зависимости от целевого устройства.
Автоматический путь для тех, кто готов настроить сборку: npm-пакет critical от Addy Osmani. Он открывает страницу в headless-браузере, определяет видимую область и вытаскивает только нужные правила.
npm install --save-dev critical
npx critical https://example.ru/ --base ./dist/ --inline --target index.html --width 1300 --height 900
Пакет penthouse работает похоже, но даёт больше контроля через API и годится, когда критический CSS нужно генерировать программно для десятков шаблонов сразу, например для каждой страницы услуги в CPT.
Ручной способ подходит для простого сайта без сборки, где страниц немного и дизайн меняется редко. Порядок такой:
- Открыть страницу, прокрутить до конца первого экрана, включить в DevTools показ границы viewport.
- Через вкладку Elements пройтись по видимым блокам: шапка, hero, первая секция, и выписать их CSS-классы.
- Собрать из основного файла только правила для этих классов плюс базовые сбросы (reset, box-sizing, шрифты, цвета переменных).
- Вставить получившийся CSS инлайном в тег style внутри head, до подключения основного файла.
Для типового лендинга малого бизнеса критический блок обычно укладывается в 8-14 килобайт несжатого CSS. Если получилось 40 и больше, скорее всего в отбор попало лишнее, стоит пройтись по списку правил ещё раз.
Как подключить остаток асинхронно и не поймать прыжок вёрстки
Критические стили лежат инлайном в head, всё остальное грузим так, чтобы оно не блокировало первую отрисовку. Стандартный приём:
<link rel="preload" href="/wp-content/themes/saitfix/assets/css/main.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet" href="/wp-content/themes/saitfix/assets/css/main.css">
</noscript>
Браузер грузит файл с приоритетом preload, не блокируя рендер, а в момент onload превращает его в обычный stylesheet. Тег noscript нужен для случаев, когда JavaScript отключён: без него сайт останется без стилей вне видимой области навсегда.
Главный риск такого подхода, сдвиг вёрстки (CLS) в момент, когда основной CSS наконец применяется: элементы ниже первого экрана меняют размеры или положение. Три способа снизить риск:
- держать критический CSS максимально близким к финальным стилям блока, а не упрощённой версией,
- задавать явные размеры или min-height контейнерам ниже первого экрана до применения основного CSS,
- проверять итог через Lighthouse и через ручную прокрутку с включённым троттлингом сети на Slow 3G.
Если после внедрения CLS вырос, а не упал, чаще всего дело именно в этом: критический CSS не совпадает по деталям с основным файлом, и элементы дёргаются при подмене. Подробнее про саму метрику и типовые причины скачков я разбирал в статье про CLS и прыгающую вёрстку.
Шрифты и font-display: сосед по проблеме
Часто то, что кажется проблемой CSS, на самом деле проблема шрифтов. Даже с идеальным критическим CSS браузер может ждать загрузки веб-шрифта, прежде чем отрисовать текст, если для @font-face не задан font-display.
Правило простое: font-display: swap показывает текст системным шрифтом сразу, а веб-шрифт подменяет его, как только загрузится. font-display: optional идёт дальше и вовсе не ждёт шрифт, если он не успел загрузиться быстро, жертвуя красотой ради скорости.
@font-face {
font-family: "Inter";
src: url("/wp-content/themes/saitfix/assets/fonts/inter-regular.woff2") format("woff2");
font-display: swap;
font-weight: 400;
}
Для самого важного шрифта, того, которым набран заголовок первого экрана, имеет смысл добавить preload:
<link rel="preload" href="/wp-content/themes/saitfix/assets/fonts/inter-regular.woff2"
as="font" type="font/woff2" crossorigin>
Это поднимает приоритет загрузки файла шрифта выше обычного CSS-запроса и часто даёт больше выигрыша в LCP, чем сама возня с критическим CSS, особенно если заголовок набран нестандартным начертанием. Основы метрик первого экрана и того, на что вообще стоит смотреть, собраны в статье про Core Web Vitals простыми словами.
Когда всё это не нужно
Критический CSS не бесплатное улучшение, у него есть эксплуатационная цена: при каждой правке вёрстки нужно помнить, что инлайновый блок в head может устареть и рассинхронизироваться с основным файлом. На проекте с частыми правками дизайна это превращается в отдельную регулярную задачу.
Если сайт уже отдаёт один небольшой CSS-файл, minified и в gzip или brotli укладывается в 15-25 килобайт, а LCP по данным Search Console или PageSpeed уже ниже 2,0-2,5 секунды, критический CSS почти наверняка не даст заметной разницы, а сложности добавит. В таких случаях эффективнее один раз почистить неиспользуемые правила и минифицировать файл, чем городить асинхронную схему подключения. Про саму минификацию я отдельно писал в статье про сжатие CSS и JavaScript, а общий порог, ниже которого LCP уже не считается проблемой, разбирал в статье про LCP больше 2,5 секунды.
Сравнение подходов
| Способ | Точность | Время на внедрение | Риск при правках дизайна |
|---|---|---|---|
| Ручной отбор правил | средняя, зависит от внимательности | 1-3 часа на шаблон | высокий, легко забыть обновить |
| Пакет critical / penthouse | высокая, автоматический пересчёт | 2-4 часа на настройку сборки | низкий при регенерации в CI |
| Плагин WordPress (Autoptimize, WP Rocket) | средняя, чёрный ящик | 15-30 минут | средний, иногда ломает верстку сам |
| Ничего не делать, один общий файл | не применимо | 0 | нет риска, но и нет выигрыша |
Чек-лист перед сдачей работы
- Coverage в DevTools показывает, что критический блок реально используется на первом экране, а не притянут за уши.
- PageSpeed Insights больше не показывает основной CSS-файл в списке «render-blocking resources» на первом месте.
- Lighthouse CLS не вырос по сравнению с замером до внедрения.
- Тег noscript с fallback-стилями на месте и проверен с отключённым JavaScript.
- Шрифт первого экрана подключён через preload, а font-display выставлен для всех @font-face.
- Изменение любого видимого блока первого экрана сопровождается пересборкой критического CSS, а не остаётся забытым до следующего аудита.
Что делать дальше
Если после всех правок PageSpeed всё ещё жалуется на скорость, вероятно, дело не в CSS, а в других узких местах: тяжёлых картинках, синхронных сторонних скриптах или медленном TTFB на самом хостинге. Возиться с критическим CSS ради пары десятых секунды, пока сервер отвечает три секунды, не имеет смысла, сначала чините самое дорогое узкое место.
По моему опыту порядок работ должен быть обратным тому, что интуитивно хочется сделать сначала. Сервер и TTFB, потом картинки и шрифты, и только в последнюю очередь тонкая настройка критического CSS. Причина простая: TTFB в 2-3 секунды съедает весь запас времени, который критический CSS способен сэкономить, и тогда работа по выделению стилей превращается в занятие ради галочки в отчёте, а не ради реального ускорения сайта для живого посетителя.
Если хочется, чтобы аудит скорости и внедрение критического CSS сделал кто-то, кто уже проходил это на десятках сайтов, посмотрите мои тарифы на обслуживание или напишите через форму на сайте, приложив ссылку на текущий отчёт PageSpeed.
Частые вопросы
Что такое критический CSS
Стили, без которых первый экран не нарисуется правильно. Его вставляют прямо в HTML, а полный файл стилей грузят следом асинхронно, чтобы он не блокировал отрисовку.
Как понять, что стили блокируют отрисовку
Открыть инструменты разработчика и посмотреть покрытие CSS: если файл на 80-90 процентов не используется на странице, браузер ждёт ради ничего.
Нужен ли для этого плагин
Не обязательно. Плагины собирают критический CSS автоматически и часто ошибаются на нетиповых шаблонах. Ручной сбор для трёх-четырёх типов страниц надёжнее и делается один раз.
Когда критический CSS не нужен
Когда LCP уже держится ниже 2-2,5 секунды. Тогда выигрыш будет в пределах погрешности, а сложность поддержки вырастет заметно.