Bcorrections

Render-blocking ресурсы: как ускорить first paint без жертв

Что такое render-blocking CSS и JS, почему они портят LCP, и какие практические техники их устраняют — preload, async/defer, critical CSS, code splitting.

«Сайт долго грузится» — самая частая жалоба пользователей и самая частая причина потери позиций в SEO. И в 80% случаев виновник один: render-blocking ресурсы. Это CSS и JS файлы, которые браузер должен скачать и обработать перед тем, как нарисовать пользователю хоть что-то на экране.

В этой статье — что такое render-blocking, как их найти и какими техниками устранить без потери функциональности сайта.

Как работает рендеринг страницы

Чтобы понять проблему, нужно понимать как браузер строит страницу.

  1. Браузер запрашивает HTML
  2. Парсит HTML, строит DOM-дерево
  3. Встречает <link rel="stylesheet"> или <script src=""> в <head>
  4. Останавливает построение и идёт скачивать ресурс
  5. Скачивает, обрабатывает (парсит CSS, выполняет JS)
  6. Возвращается к парсингу HTML
  7. Финально строит CSSOM, объединяет с DOM в Render Tree
  8. Делает Layout (geometry), Paint, Compositing
  9. Пользователь видит первый кадр

Если на шаге 3-5 ресурс скачивается медленно, пользователь смотрит на белый экран. LCP (Largest Contentful Paint) пухнет. Bounce rate растёт.

Render-blocking ресурс — любой CSS или JS, который браузер обязан скачать и обработать до начала рендеринга.

Как найти render-blocking ресурсы

Откройте PageSpeed Insights на главной вашего сайта. В разделе «Opportunities» обычно есть строка «Eliminate render-blocking resources» с списком файлов и сколько времени можно сэкономить.

Также:

  • Chrome DevTools → Network, перезагрузите страницу. Файлы с типом script и stylesheet, загруженные ДО события DOMContentLoaded — render-blocking.
  • Chrome DevTools → Coverage (открыть через Cmd+Shift+P → «Show Coverage»). Покажет какой % каждого ресурса фактически использовался на текущей странице. Если у вас 200 КБ CSS, а используется 15 КБ — есть что оптимизировать.
  • Lighthouse → Audits → Performance — то же что PageSpeed но локально.

Техника 1: async и defer для JS

Это самая базовая оптимизация, которую все знают, но не все применяют правильно.

<script src="analytics.js"></script>           <!-- блокирует -->
<script src="analytics.js" async></script>     <!-- скачивается параллельно, выполняется как готов -->
<script src="analytics.js" defer></script>     <!-- скачивается параллельно, выполняется после DOMContentLoaded -->

Когда async:

  • Аналитика (Я.Метрика, GA, Hotjar)
  • Виджеты соцсетей
  • Любой JS, который не зависит от DOM и от других скриптов

Когда defer:

  • JS, который работает с DOM (находит элементы, навешивает обработчики)
  • JS, который должен выполниться в определённом порядке (несколько defer-скриптов выполняются последовательно в порядке появления в HTML)
  • Полифиллы и тяжёлые библиотеки

Когда оставить блокирующим:

  • Очень редко. Только если скрипт критически нужен для отрисовки above-the-fold контента и нельзя обойтись CSS.

Техника 2: критический CSS inline в HTML

CSS блокирует рендеринг иначе, чем JS — браузер должен дождаться полного CSSOM перед первым paint. Поэтому даже маленький блокирующий CSS — это +300-500 мс к LCP на медленном соединении.

Решение: критический CSS — стили, нужные только для above-the-fold блока, инлайнятся прямо в <head> через <style>. Остальные CSS подгружаются асинхронно.

<head>
  <style>
    /* Critical CSS: header, hero, главные кнопки. Обычно 8-15 КБ. */
    body { font: 16px/1.5 sans-serif; margin: 0; }
    .header { padding: 20px; background: #fff; }
    .hero { padding: 60px 20px; text-align: center; }
    /* ... */
  </style>

  <!-- Остальной CSS — асинхронно -->
  <link rel="preload" href="/styles/main.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/styles/main.css"></noscript>
</head>

Сложность: критический CSS меняется при изменении дизайна. Поддержка вручную невозможна. Используйте автоматические инструменты:

  • Critters (npm package, интегрируется в build)
  • PurgeCSS + Critical для статических сайтов
  • Next.js делает это автоматически через CSS Modules + RSC
  • Astro инлайнит критический CSS из default scope автоматически

Техника 3: code splitting в JS

Если у вас одно большое bundle.js весом 800 КБ, оно блокирует/тяжелит загрузку каждой страницы — даже там, где нужны только 50 КБ функционала.

Решение: разбивайте код на чанки по маршрутам и фичам.

В Next.js это работает из коробки — каждая страница получает свой chunk + общий shared chunk. Дополнительно для тяжёлых компонентов:

import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('./HeavyChart'), {
  ssr: false,
  loading: () => <Skeleton />
});

HeavyChart.js не попадёт в основной бандл — будет загружен отдельным запросом только когда страница его покажет.

В React без Next.jsReact.lazy() + Suspense:

const HeavyChart = React.lazy(() => import('./HeavyChart'));
<Suspense fallback={<Skeleton />}>
  <HeavyChart />
</Suspense>

В Vue 3defineAsyncComponent.

Техника 4: preload ключевых ресурсов

Если ресурс точно понадобится для рендера, можно сказать браузеру «начни скачивать его сразу, не жди парсинга HTML».

<head>
  <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/hero-image.jpg" as="image">
</head>

Это особенно важно для:

  • Шрифтов (без preload браузер находит @font-face в CSS только после загрузки CSS — FOUT/FOIT)
  • Главного hero-изображения (LCP кандидат)
  • Критичных JS-чанков (если используете code splitting)

Не злоупотребляйте preload — каждый preload отъедает приоритет у других ресурсов. 3-5 preload на страницу — норма, 30 — деградация.

Техника 5: третьи стороны под контроль

Третьи стороны — самый частый источник render-blocking в 2026 году. Аналитика, рекламные сети, чаты, виджеты соцсетей. Каждый виджет = +1 синхронный JS на 50-200 КБ.

Стратегии:

  1. Аудит: посмотрите все третьи стороны на сайте. Каждую — оцените: «нужна ли она реально». Часто 60% можно удалить без потерь.
  2. Async для всех: добавьте async или defer ко всем третьесторонним скриптам.
  3. Lazy loading: некоторые виджеты можно загружать только когда нужны. Например, чат интеркома — после первого взаимодействия пользователя, не сразу.
  4. Self-hosting аналитики: вместо <script src="https://google-analytics.com/..."> — проксируйте через свой домен. Будет быстрее (один TCP-handshake), стабильнее (не зависит от блокировщиков), приватнее.
  5. Tag manager только если реально нужен: Google Tag Manager — это +200 КБ на каждую страницу. Если у вас 3 скрипта, проще включить их напрямую.

Техника 6: HTTP/2 и HTTP/3

Это инфраструктурный шаг, но он влияет на render-blocking.

В HTTP/1.1 браузер ограничен 6 параллельными запросами к одному домену. Если у вас в head 10 ресурсов — 4 ждут очереди. Render-blocking накапливается.

В HTTP/2 — мультиплексирование, один TCP-канал передаёт все ресурсы одновременно. В HTTP/3 (QUIC) — дополнительно быстрое восстановление при потере пакетов.

Что нужно сделать:

  • Включить HTTP/2 в nginx (он по умолчанию есть с 1.13+, проверьте listen 443 ssl http2;)
  • HTTP/3 пока более экспериментально, но nginx 1.25+ его поддерживает: listen 443 ssl http2 http3;
  • CDN — большинство современных CDN (Cloudflare, BunnyCDN, KeyCDN) поддерживают HTTP/3 из коробки

Эффект: на сайтах с 20+ ресурсами в head ускорение LCP на 200-500 мс просто от включения HTTP/2.

Реальный пример

Типичный сайт «до»:

  • 1 главный CSS — 145 КБ, render-blocking
  • 1 jQuery — 88 КБ, render-blocking
  • 1 main.js — 320 КБ, render-blocking
  • 4 third-party (analytics, chat, Hotjar, ads) — 280 КБ суммарно
  • LCP: 4.2 сек (мобильный, 4G)

«После» оптимизации:

  • Critical CSS inline 12 КБ + main.css preload 145 КБ
  • jQuery вообще удалили (не используется в коде)
  • main.js — defer, разбит на 6 чанков
  • Все third-party — async или удалены
  • LCP: 1.8 сек

Эффект: bounce rate упал на 32%, конверсия выросла на 18%, позиции в Яндексе по 60% запросов выросли в среднем на 4.

Резюме

Render-blocking ресурсы — главная причина медленного first paint. Устраняются они комбинацией техник: async/defer для JS, critical CSS inline, code splitting, preload, контроль третьих сторон, HTTP/2.

Большинство — это однократные оптимизации, которые потом стабильно работают. Час работы инженера может сэкономить пользователям часы суммарного ожидания.

Хотите аудит производительности? Напишите нам — бесплатный экспресс-аудит за 2 рабочих дня.

Веб-разработка

Это часть нашей услуги Разработка сайтов

Сайты под ключ, сразу готовые к SEO и AI-поиску

Перейти к услуге →
Идём дальше?

Нужна пара экспертных глаз на ваш проект?

Делаем экспресс-аудит за 2 рабочих дня: показываем где сайт теряет трафик и что исправить в первую очередь.

Обсудить проект