Цель оптимизации CSS/JS — не «чем меньше файлов, тем лучше», а чтобы при первой отрисовке загружались только нужные байты. Четыре основных правила: критический CSS встроить в head (примерно до 15 КБ), некритический CSS грузить асинхронно через media=print onload, JS для интерактива на первом экране подключать с defer, а не с async, аналитику и рекламные скрипты откладывать до после первого экрана через requestIdleCallback. Контринтуитивный вывод: добавить async ко всем JS — не бесплатный обед, нарушенный порядок выполнения заставит jQuery и зависящие от него плагины массово выдавать ошибки; ещё один контринтуитивный момент: объединение в один CSS-файл не всегда быстрее, потому что теряется разбиение на блоки для долгосрочного кеширования.
Сначала вывод: Цель оптимизации CSS/JS — не «чем меньше файлов, тем лучше», а чтобы при первой отрисовке загружались только нужные байты. Четыре основных правила: критический CSS встроить в head (примерно до 15 КБ), некритический CSS грузить асинхронно через media=print onload, JS для интерактива на первом экране подключать с defer, а не с async, аналитику и рекламные скрипты откладывать до после первого экрана через requestIdleCallback. Контринтуитивный вывод: добавить async ко всем JS — не бесплатный обед, нарушенный порядок выполнения заставит jQuery и зависящие от него плагины массово выдавать ошибки; ещё один контринтуитивный момент: объединение в один CSS-файл не всегда быстрее, потому что теряется разбиение на блоки для долгосрочного кеширования.
I. Почему CSS/JS блокируют первую отрисовку
У браузера есть жёсткое правило отрисовки HTML: CSS блокирует рендеринг, JS блокирует парсинг. Пока в head висит недокачанный CSS, браузер не рисует ни одного пикселя; пока в body есть script без async/defer, парсинг останавливается на нём и ждёт загрузки и выполнения JS. Эти два блокирования складываются — вот корневая причина медленного FCP (First Contentful Paint).
Типичная проблема сайтов на WordPress: тема подключает 5 CSS-файлов, плагины добавляют ещё 8 JS — и каждый из них несжатый и необъединённый исходник. В head выстраивается длинная очередь из link и script, и только на их загрузку уходит 3–5 секунд. Оптимизация — это не «собрать всё в один файл», а распределить ресурсы: что должно загрузиться сразу, а что может подождать, пока отрисуется первый экран. Нормативы Core Web Vitals смотрите в Оптимизация Core Web Vitals, как собрать стек WordPress см.Технологический стек WordPress.
Тип блокировки
Поведение браузера
Затрагиваемые метрики
Что делать
Внешний CSS в head
Блокирует рендеринг до полной загрузки
FCP, LCP
Критический CSS встроить, остальное — асинхронно
script без defer в body
Блокирует парсинг HTML
FCP, TTI
Всем добавить defer или перенести в
перед
Синхронный XHR-запрос
Блокирует главный поток
INP, TTI
Перевести на асинхронный fetch
Загрузка шрифтов
Текст может быть невидим
LCP
font-display:swap+preload
сторонние скрипты
Блокирует парсинг или главный поток
INP, TBT
Отложить или разместить через GTM
II. Встраивание критического CSS: стили первого экрана прямо в head
Критический CSS (Critical CSS) — это минимальный набор стилей, нужный для отрисовки содержимого первого экрана: обычно header, hero-блок, первый абзац текста, стили кнопок, примерно 10–20 КБ. Если встроить эту часть в тег style в HTML, браузеру не придётся отправлять отдельный запрос за CSS, и FCP ускорится на 0,5–1 секунду.
Контринтуитивный момент:встраивание — это не когда весь CSS запихивают внутрь。Многие ставят автоплагин «встроить весь CSS» — и HTML вырастает с 50 КБ до 300 КБ, первый экран почти не ускоряется, а кэш перестаёт работать. Правильно встраивать только CSS первого экрана (above-the-fold), остальной CSS оставить внешним, но грузить асинхронно. В WordPress для этого есть плагин CriticalCSS или PurgeCSS — они извлекают стили автоматически. Если делать вручную, стили первого экрана обычно занимают 15–25% всего CSS. О стратегиях кэширования в WP см.Стратегия кэширования сайта.
Как сделать
объём head
улучшение FCP
Риск
без критического CSS
0 КБ встроено
базовый вариант
CSS блокирует рендеринг
встроить весь CSS
100–300 КБ
Минус
HTML слишком большой, кэш не работает
встроить только CSS первого экрана
10–20 КБ
0,5–1 секунда
нужно поддерживать таблицу стилей первого экрана
встроить + остальное асинхронно
10–20 КБ
0,8–1,5 секунды
нужна защита от FOUC
III. Асинхронная загрузка некритичного CSS: трюк с media=print onload
После встраивания критического CSS остальной CSS сайта не должен блокировать рендеринг. Самый распространённый приём — написать тег link как media=”print” onload=”this.media=’all'”: браузер сначала загружает его как стили для печати (не блокирует рендеринг), а после загрузки переключает обратно на экранные стили. Это широко проверенный хак, его поддерживают все современные браузеры.
Нужен запасной вариант через noscript — чтобы стили отображались и в старых браузерах с отключённым JS. Конкретный шаблон: <link rel=”stylesheet” href=”main.css” media=”print” onload=”this.media=’all'”> плюс <noscript><link rel=”stylesheet” href=”main.css”></noscript>. Учтите: этот приём вызывает кратковременный FOUC (вспышку нестилизованного контента). Вместе со встроенным критическим CSS стили первого экрана уже есть, поэтому вспышка происходит только ниже первого экрана и почти незаметна. Как настроить кэширование на CDN, см.Глобальное ускорение CDN.
Способ загрузки
блокирует ли рендеринг
совместимость с браузерами
Когда подходит
обычный внешний CSS
блокирует
Всё
критический CSS (но его лучше встроить)
переключение media=print onload
не блокирует
все современные браузеры
некритичный CSS всего сайта
rel=preload+onload
не блокирует
Chrome/FF/Safari14+
нужен точный контроль момента загрузки
динамическая вставка через JS
не блокирует
Всё
загрузка сторонних компонентов по мере необходимости
встроить в тег style
срабатывает сразу
Всё
только для критического CSS
IV. defer и async для JS: быстрее — не всегда лучше
У тега script три режима загрузки: без атрибутов (блокирует парсинг), defer (скачивание не блокирует, выполнение по порядку после разбора HTML) и async (скачивание не блокирует, выполнение сразу после загрузки, порядок не гарантирован). Многие читают в туториалах «добавляйте async ко всем JS» — это ошибка: async не гарантирует порядок выполнения, и если jQuery выполнится раньше плагина, будет ошибка.
Правильное распределение: скрипты для интерактива первого экрана (меню навигации, карусель, валидация форм) подключайте через defer — они выполнятся по порядку до DOMContentLoaded; чистая аналитика, чаты и пиксели — через async или requestIdleCallback с задержкой. Конкретный пример: Google Analytics и Hotjar с async или обёрнутые в setTimeout с задержкой 2 секунды никак не влияют на функциональность, но срезают TBT (общее время блокировки) на 200–400 мс. Как этим управлять в GTM, см.Управление GTM.
Тип скрипта
Рекомендуемый атрибут
Момент выполнения
На что обратить внимание
jQuery и зависимые плагины
defer
Выполняются по порядку после разбора DOM
Обязательно defer, async нельзя
Интерактив первого экрана (меню/карусель)
defer
До DOMContentLoaded
События привязаны до клика пользователя
Google Analytics
async или задержка
Выполнение в простое
Задержка не влияет на сбор данных
Hotjar/Clarity
Задержка 2 секунды или idle
После первого экрана
Чтобы не портить INP
Сторонние чаты и попапы
Загрузка после действия пользователя
После прокрутки на 30%
Отложенная загрузка не влияет на конверсию
Небольшие встроенные скрипты
Без атрибута
Выполняются сразу
Уложить в 1 КБ
Пять: объединение и сжатие — долгий кеш важнее разового размера
Сжатие (minify) — бесспорная выгода: убираем комментарии и пробелы, объём CSS/JS падает на 30–40%. А вот объединение (concatenate) даёт контринтуитивный эффект: соберёте весь CSS в один файл — первый визит быстрый, но при каждой правке одной строки пользователь заново скачивает весь файл, и долгий кеш перестаёт работать. Правильно — разбить на несколько стабильных блоков: CSS фреймворка, CSS темы и CSS страницы отдельно; общая часть кешируется надолго, страничная подгружается по необходимости.
В экосистеме WordPress для объединения и сжатия используют Autoptimize или W3 Total Cache: включите «Объединять CSS», «Объединять JS» и «minify», но выключите опасную опцию «объединять весь JS в head». Конкретная точка проверки: на главной в DevTools Network число запросов CSS падает с 10 до 2–3, запросов JS — с 8 до 3–4, при этом нет FOUC и ошибок в консоли. Безопасность и мониторинг сайта см.Защита сайта и Оповещения мониторинга сайта.
Действие
Выгода по объёму
Риск
Рекомендуемая настройка
Минификация CSS
-30–40%
Почти нет
Включить
Минификация JS
-30–40%
Теряются source map
Включить
Объединение CSS
Меньше запросов
Кеш часто сбрасывается
Объединять частично, не всё
Объединение JS в head
Меньше запросов
Блокирует рендеринг
Запрещено
Объединение JS + defer
Меньше запросов и без блокировки
Порядок зависимостей
Включать осторожно, проверять консоль
Удаление неиспользуемого CSS
-40–60%
Можно удалить динамические стили
PurgeCSS с постепенным включением
FAQ: частые вопросы
Если всем JS поставить async, будет быстрее всего?
Нет. async скачивает скрипт, не блокируя HTML, но выполняет сразу после загрузки и не гарантирует порядок. Если поставить async для jQuery и зависящих от него плагинов, порядок выполнения сломается и посыплются ошибки $ is not defined. Правильно так: скрипты интерактива первого экрана — через defer (выполняются по порядку), аналитика и реклама — через async или отложенную загрузку. defer и async не исключают друг друга, но применять их нужно по роли скрипта.
Сколько КБ критического CSS встраивать?
10–20 КБ — золотая середина. Слишком мало инлайна — на первом экране всё равно мелькает FOUC. Больше 30 КБ — раздувается сам HTML, и кэш перестаёт работать. В критический CSS включайте только шапку, hero-блок, текст первого экрана и стили кнопок — это 15–25% всего CSS. Извлеките его через CriticalCSS, а потом пройдитесь руками и удалите классы, которые на первом экране не нужны.
Если объединить CSS в один большой файл, загрузка ускорится?
При первом визите запросов меньше, но с долгим кэшированием всё наоборот хуже. Меняете одну строку — hash всего файла меняется, и все пользователи скачивают его заново. Правильно разбить на три части: CSS фреймворка (не меняется долго), CSS темы (обновляется раз в квартал) и CSS страниц (подгружается по мере надобности). Общее кэшируется надолго, страничное подгружается по необходимости. Объединяйте только однотипное, не всё подряд.
Какие подводные камни у приёма media=print onload?
Два. Первый: короткий FOUC — вспышка нестилизованного текста. Если критический CSS заинлайнен, на первом экране стили уже есть, и вспышка видна только ниже, где её почти не заметно. Второй: обязателен запасной вариант в noscript — старые браузеры с отключённым JS тоже должны видеть стили. Шаблон такой: в теге link пишете media=print onload=this.media=’all’, а внутри тега noscript — обычный media=all.
Autoptimize или WP Rocket — что выбрать?
Autoptimize бесплатный и лёгкий: только объединяет и сжимает CSS/JS. Подойдёт сайтам, где кэш страниц уже настроен. WP Rocket стоит около 59 долларов в год и включает кэш страниц, ленивую загрузку и оптимизацию базы — работает сразу из коробки. Если вы один в команде, берите WP Rocket, чтобы не крутить параметры вручную. Если кэш уже есть, хватит Autoptimize. И в обоих не включайте опасные опции вроде «весь JS в head».
Как проверить результат после оптимизации CSS/JS?
В Lighthouse смотрите три аудита: «Удалите неиспользуемый JavaScript», «Удалите неиспользуемый CSS» и «Сократите время работы главного потока». Цели: неиспользуемый CSS меньше 20 КБ, неиспользуемый JS меньше 50 КБ, работа главного потока меньше 200 мс. Затем в DevTools Network проверьте, что на главной осталось 2–3 запроса CSS и 3–4 запроса JS, а в консоли нет красных ошибок. И наконец, в CrUX посмотрите, укладывается ли 75-й процентиль FCP в 1,8 секунды.
6. Подсказки о ресурсах: как использовать preload, preconnect и dns-prefetch
Кроме разделения по приоритетам есть ещё один уровень оптимизации — подсказки о ресурсах (resource hints). preload нужен для ключевых ресурсов, которые точно понадобятся на первом экране: LCP-изображения, ключевого шрифта, JS для интерактива на первом экране. В head пишете <link rel=”preload” as=”image” href=”hero.webp”>, и браузер скачает ресурс заранее с высоким приоритетом. Злоупотреблять preload — частая ошибка: preload всего подряд равносилен отсутствию preload, потому что засоряется планировщик браузера. Не больше трёх preload на страницу.
preconnect используется для сторонних доменов — CDN, шрифтов и аналитики. В head добавьте <link rel=”preconnect” href=”https://cdn.example.com”>, и браузер заранее выполнит DNS, TCP и TLS-рукопожатие, сэкономив 300–500 мс при реальном запросе ресурса. dns-prefetch — упрощённая версия preconnect: только DNS-разрешение, для старых браузеров. Конкретный пример настройки: в head интернет-магазина добавьте по одному preconnect для домена CDN и домена шрифтов, а для остальных сторонних доменов — только dns-prefetch.
Тип подсказки
Что даёт
Подходящие ресурсы
Лимит
rel=preload
Приоритетная предзагрузка
LCP-изображение, ключевые шрифты, JS первого экрана
Не более 3 на страницу
rel=preconnect
Заранее выполняет DNS/TCP/TLS
Домены CDN, шрифтов, сторонних API
Не более 4 на страницу
rel=dns-prefetch
Только DNS-разрешение
Второстепенные сторонние домены
Без ограничений, для старых браузеров
rel=prefetch
Предзагрузка следующей страницы в простое
Страницы, куда пользователь может перейти дальше
Осторожно, расходует трафик
В заключение
Суть оптимизации CSS/JS — не сжать всё подряд, а распределить приоритеты. То, что нужно для первого экрана, встройте инлайном или добавьте в preload, остальное отложите до отрисовки первого экрана. Если эта логика ясна, инструменты — лишь средство; если нет, сколько бы плагинов вы ни поставили, проблема просто переедет в другое место.
Три шага на практике: первый — на этой неделе прогоните главную через Lighthouse и посмотрите аудиты по неиспользуемым CSS/JS; второй — включите minify и объединение в Autoptimize или WP Rocket, но осторожно, сначала проверьте, что в консоли нет ошибок; третий — встройте критический CSS для первого экрана инлайном и отложите скрипты аналитики и чата. Через две недели перепроверьте FCP и TBT.
Фраза, которую стоит запомнить: цель оптимизации CSS/JS — не минимум файлов, а чтобы за те 1,8 секунды первого экрана браузер получил только те байты, которые нужны ему прямо сейчас.
craterЭксперт Crater
Официальный аккаунт организации · crater Crater
环形山 (Crater) — компания, которая помогает выходить на зарубежные рынки: разработка сайтов на WordPress, Google SEO и комплексный рост в GEO. Мы работаем с умными устройствами, промышленным оборудованием, SaaS и новой энергетикой.
Возможности продуктаБелая книга по методологииОтраслевые отчёты