Bcorrections

Critical Rendering Path: как браузер рисует первый кадр

Что происходит между «получил HTML» и «пользователь видит контент». Пошаговый разбор и где обычно теряется время.

Между моментом «браузер получил первый байт HTML» и моментом «пользователь видит контент» проходит много невидимой работы. Понимание этой цепочки — Critical Rendering Path, CRP — отличает SEO-специалиста, который оптимизирует Core Web Vitals наугад, от того, кто знает где именно искать тормоза.

В этой статье — пошаговый разбор CRP и практические выводы для каждого этапа.

Этапы CRP

Условно их пять:

  1. Construct the DOM — построение дерева DOM из HTML
  2. Construct the CSSOM — построение дерева стилей из CSS
  3. Render Tree — объединение DOM и CSSOM
  4. Layout — вычисление геометрии (позиции, размеры элементов)
  5. Paint + Composite — отрисовка пикселей на экране

JavaScript встраивается между этапами и может всё сломать. Разберём по порядку.

Этап 1: DOM construction

Браузер получает HTML побайтово. Парсер построчно превращает теги в узлы DOM-дерева.

Что блокирует:

  • Встретил <script> без async/defer — останавливает парсинг, скачивает JS, выполняет, возвращается
  • Встретил <link rel="stylesheet"> — продолжает парсить, но дальше не сможет начать рендер без CSSOM
  • Встретил <iframe> — открывает отдельный child contexte, не блокирует основной

Что ускорить:

  • defer или async на скриптах (см. render-blocking ресурсы)
  • Стримминг HTML с сервера (отдавать HTML по мере готовности, не дожидаясь полной страницы)
  • Уменьшение размера HTML (gzip/brotli компрессия)

Типичный HTML-документ в 50-100 КБ парсится за 10-30 мс. Это редко узкое место. Узкое место обычно — скачивание HTML по сети.

Этап 2: CSSOM construction

CSS блокирует рендер. Браузер обязан построить полный CSSOM перед первой отрисовкой.

Как это работает:

  1. Браузер встречает <link rel="stylesheet" href="main.css"> в HTML
  2. Отдельным запросом качает main.css
  3. Парсит CSS, строит дерево правил
  4. Если в CSS есть @import — рекурсивно повторяет (медленно, см. @import в CSS)

Что блокирует:

  • Большие CSS-файлы (200+ КБ некомпрессированных)
  • Цепочки @import
  • CSS с внешних доменов (требует DNS, handshake)
  • CSS, заблокированный медленным сервером

Что ускорить:

  • Inline critical CSS в HTML — убирает блокировку для above-the-fold
  • Preload основного CSS — <link rel="preload" href="main.css" as="style">
  • Brotli-сжатие
  • Удаление неиспользуемого CSS (PurgeCSS)

Этап 3: Render Tree

Когда DOM и CSSOM готовы, браузер строит Render Tree — это DOM, к каждому узлу которого применены вычисленные стили. Скрытые элементы (display: none) в Render Tree не попадают.

Что блокирует:

  • DOM ещё не готов (тяжёлый HTML, синхронные скрипты)
  • CSSOM ещё не готов (большой CSS, @import)

Этап быстрый сам по себе (5-20 мс), просто ждёт DOM + CSSOM.

Этап 4: Layout (Reflow)

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

Что замедляет:

  • Тысячи узлов в DOM (страница с 50 000 элементов будет считаться долго)
  • Сложные flexbox/grid с пересчётом
  • Изменение размера viewport (resize event)
  • JavaScript, который меняет геометрию между paint'ами (например, добавляет элементы динамически)

Что ускорить:

  • Минимизировать DOM — простая структура, без лишних обёрток
  • Использовать contain: layout style на изолированных компонентах — браузер не будет пересчитывать всё, если меняется один блок
  • Не делать «forced layouts» в JS — это когда вы меняете элемент, тут же читаете его геометрию (offsetWidth, clientHeight). Это заставляет браузер пересчитывать заново.

Группируйте чтение и запись:

// Плохо — N reflows
elements.forEach(el => {
  el.style.width = el.offsetWidth + 10 + 'px';  // read+write на каждом элементе
});

// Хорошо — 1 reflow
const widths = elements.map(el => el.offsetWidth);  // все reads
elements.forEach((el, i) => {
  el.style.width = widths[i] + 10 + 'px';  // все writes
});

Этап 5: Paint + Composite

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

Что замедляет:

  • Большие области с тяжёлыми стилями (тени, фильтры, градиенты)
  • Анимации width, height, top, left — требуют переотрисовки геометрии
  • backdrop-filter — самый дорогой эффект в современном CSS

Что ускорить:

  • Анимации только через transform и opacity — они работают на GPU, не требуют paint
  • will-change: transform на анимируемых элементах — даёт hint браузеру выделить отдельный compositor layer
  • Реже использовать backdrop-filter (если очень нужно — на маленьких областях)
  • Использовать content-visibility: auto для off-screen блоков — пропустит paint того, что не видно

Где JavaScript встраивается

JS может встроиться в любой момент CRP и всё ломать.

Синхронный JS в <head>:

Блокирует парсинг DOM. Парсер останавливается, JS скачивается, парсится, выполняется. Только потом парсер продолжает.

<head>
  <script src="heavy.js"></script>   <!-- блокирует, плохо -->
  <script src="heavy.js" defer></script>  <!-- ожидает DOM, потом выполняется -->
  <script src="heavy.js" async></script>  <!-- выполняется как готов, может прерывать -->
</head>

JS, манипулирующий DOM:

Если JS добавляет элементы — Layout пересчитывается. Если меняет стили — Paint пересчитывается. Минимизируйте JS-манипуляции DOM, особенно во время загрузки.

JS, измеряющий геометрию:

element.offsetWidth, getBoundingClientRect() — это «sync layout». Заставляет браузер немедленно пересчитать Layout. Если делать много раз — большая нагрузка.

Метрики и где смотреть

В Chrome DevTools → Performance:

  1. Запишите загрузку страницы (3-5 секунд)
  2. Откройте Main thread timeline
  3. Цветовая разметка покажет:
    • Жёлтый (Scripting) — JS
    • Фиолетовый (Rendering) — Layout
    • Зелёный (Painting) — Paint
    • Синий (Loading) — сеть

Где какой цвет занимает много места — там узкое место.

Long Tasks (>50 мс) маркируются красным треугольником в timeline. Это блокирует main thread, ухудшает INP и LCP.

Связь с Core Web Vitals

CRP напрямую влияет на все три метрики:

  • LCP — это момент когда главный визуальный элемент завершил Layout + Paint. Чем быстрее CRP — тем лучше LCP.
  • CLS — если Layout пересчитывается после первого Paint, элементы могут «прыгать», CLS растёт.
  • INP — если JS-handler заставляет браузер делать Layout/Paint больше одного кадра — INP падает.

Подробнее — в Core Web Vitals 2026.

Резюме

Critical Rendering Path — это не теоретическая концепция, а конкретная цепочка операций, которую можно ускорить пошагово:

  1. Стримминг + compression HTML
  2. Inline critical CSS + preload остального
  3. Defer/async JS
  4. Минимизация DOM
  5. GPU-only animations (transform/opacity)

Понимание CRP позволяет оптимизировать целенаправленно, а не «по списку из PageSpeed Insights».

Хотите детальный разбор CRP вашего сайта? Напишите нам. Бесплатно за 2 рабочих дня.

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

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

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

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

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

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

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