awesome-everything EN
↑ Обратно к восхождению

Сети и протоколы

Критический путь рендеринга и Core Web Vitals

Суть Как браузер превращает байты в пиксели — слияние DOM и CSSOM, CSS-блокировка рендеринга, preload scanner, откладывание JavaScript — и как LCP, INP и CLS измеряют пользовательский опыт этого конвейера.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Сетевая часть загрузки страницы занимает 150 мс. LCP срабатывает через 3,2 секунды. Разрыв — это конвейер рендеринга браузера, и большая его часть вызвана вашими собственными решениями: какой CSS загружать, где разместить скрипты, есть ли у изображений размеры, какой JavaScript выполняется в главном потоке до отрисовки. Понимание этого конвейера — вторая половина оптимизации загрузки страницы.

Критический путь рендеринга

После получения HTML-байтов рендеринг происходит в несколько перекрывающихся этапов:

  1. Разбор HTML → DOM. HTML-парсер строит Document Object Model по мере поступления байтов. Разбор начинается до получения полного тела — потоковый разбор.
  2. Разбор CSS → CSSOM. Когда браузер встречает тег <link rel="stylesheet">, он загружает CSS-файл и строит CSS Object Model. Ничего не отрисовывается до готовности CSSOM — CSS блокирует рендеринг. Почему? Показать страницу без стилей (FOUC — вспышка нестилизованного контента) и затем перерисовать её вызывает нестабильность макета, которая снижает воспринимаемую производительность. Это намеренно, а не ошибка.
  3. DOM + CSSOM → дерево рендеринга. Браузер объединяет DOM и CSSOM в дерево рендеринга, содержащее только видимые элементы с вычисленными стилями.
  4. Компоновка (Layout). Браузер вычисляет точное положение и размер каждого элемента.
  5. Отрисовка (Paint). Браузер растеризует дерево рендеринга в пиксели.
  6. Композитинг (Compositing). GPU-слои объединяются в финальный кадр.

JavaScript усложняет процесс: тег <script> без async или defer блокирует разбор HTML. Парсер останавливается, скрипт загружается и выполняется, затем разбор продолжается. Именно поэтому классические скрипты в <head> резко замедляют первую отрисовку.

Тип ресурсаБлокирует разбор HTML?Блокирует рендеринг?Решение
CSS (stylesheet)НетДавстроить критический CSS; preload
JS (classic, в <head>)ДаДадобавить defer или async
JS (async)ЧастичноЧастичновыполняется по готовности, не по порядку
JS (defer)НетНетвыполняется после разбора HTML, по порядку
Изображения (без размеров)НетВызывает CLSдобавить атрибуты width/height
Шрифты (WOFF2)НетВызывает FOIT/FOUTpreload + font-display:swap

Preload scanner

Браузер запускает лёгкий HTML-токенизатор, называемый preload scanner, опережая основной парсер. Он ищет URL в <link>, <script> и <img> и отправляет запросы до того, как основной парсер обработает эти теги. Без него обнаружение подресурсов было бы последовательным — каждый ресурс загружается только после того, как основной парсер достигает соответствующего тега.

Preload scanner выводится из строя:

  • JavaScript, записывающим <script src="..."> через document.write.
  • Сложной клиентской маршрутизацией, которая формирует URL после инициализации фреймворка.
  • Схемами ленивой загрузки, скрывающими URL за атрибутами data-src.

Современные фреймворки (Next.js, Astro, SvelteKit) автоматически генерируют <link rel="preload"> для компенсации.

Resource hints

ПодсказкаЭффектСтоимость
<link rel="dns-prefetch" href="//cdn.example.com">Разрешает DNS в фонеМинимальная
<link rel="preconnect" href="//cdn.example.com" crossorigin>DNS + TCP + TLS в фонеОдин простаивающий сокет на источник
<link rel="preload" as="font" crossorigin>Загружает шрифт до достижения тега парсеромПропускная способность
<link rel="modulepreload">Загружает ES-модуль + его импортыПропускная способность
<link rel="prefetch">Загружает ресурс следующей навигации (низкий приоритет)Пропускная способность в простое

Атрибут fetchpriority. Можно переопределить приоритет ресурсов по умолчанию:

  • <img src="hero.jpg" fetchpriority="high"> — hero-изображение загружается раньше прочих.
  • <script src="analytics.js" fetchpriority="low"> — некритический JS откладывается ниже CSS и шрифтов.

Core Web Vitals

Core Web Vitals от Google количественно оценивают воспринимаемую производительность. Ранжирование в поиске использует полевые данные RUM (измерения реальных пользователей через Chrome UX Report), а не синтетические оценки Lighthouse.

LCP — Largest Contentful Paint. Когда самый большой видимый элемент завершает рендеринг. Обычно это hero-изображение или основной заголовок. Хорошо: менее 2,5 с. Плохо: более 4 с. Основные причины плохого LCP: медленный TTFB сервера, ресурсы, блокирующие рендеринг и задерживающие главное изображение, большие неоптимизированные файлы изображений.

INP — Interaction to Next Paint (заменил FID в марте 2024). Наибольшая задержка между любым вводом пользователя (клик, касание, нажатие клавиши) и результирующим визуальным обновлением на протяжении всего жизненного цикла страницы. Хорошо: менее 200 мс. Плохо: более 500 мс. Основная причина: долгие задачи в главном потоке, блокирующие UI.

CLS — Cumulative Layout Shift. Неожиданное смещение видимых элементов во время загрузки страницы. Оценка: сумма (доля воздействия × доля расстояния) для каждого неожиданного смещения. Хорошо: менее 0,1. Основные причины: изображения без объявленных размеров, реклама, вставляющая контент, перетекание текста из-за веб-шрифтов.

Почему это работает

Google использует полевые данные RUM (измерения реальных пользователей из Chrome UX Report) для ранжирования, а не Lighthouse. Страница с оценкой 95 в Lighthouse на вашем ноутбуке может получить 55 в CrUX, если реальные пользователи работают на медленных Android-телефонах в слабой сети. Оптимизируйте для поля, а не лаборатории.

Викторина

Почему CSS по умолчанию блокирует рендеринг?

Проследи
1/5

Проследите, что делает браузер во время потоковой передачи HTML — от первого байта до LCP.

1
Step 1 of 5
Прибывают первые байты HTML. Что браузер делает немедленно?
2
Locked
Парсер встречает <link rel=stylesheet href=main.css>. Разбор HTML продолжается. А рендеринг?
3
Locked
Парсер встречает <script defer src=app.js>. Что происходит?
4
Locked
CSS загружен. CSSOM построен. Дерево рендеринга создано. Браузер отрисовывает первый кадр. Какая метрика срабатывает?
5
Locked
Hero-изображение загружается через 400 мс после HTML. Срабатывает LCP. Что определило, был ли LCP хорошим или плохим?
Расставь шаги по порядку

Упорядочьте эти вмешательства по влиянию на LCP (от наибольшего к наименьшему, при условии что LCP — это hero-изображение):

  1. 1 Кэшировать HTML на CDN edge, чтобы TTFB снизился с 300 мс до 20 мс
  2. 2 Добавить <link rel=preload as=image> для hero-изображения, чтобы оно загружалось параллельно с CSS
  3. 3 Конвертировать hero-изображение из JPEG в WebP (файл на 30% меньше)
  4. 4 Добавить fetchpriority=high к тегу hero <img>
  5. 5 Убрать блокирующий рендеринг скрипт аналитики из <head> (перенести в defer)
Викторина

Что измеряет INP, чего не делал FID?

Вспомните перед уходом
  1. 01
    Почему preload scanner критичен для быстрой загрузки страниц и что выводит его из строя?
  2. 02
    Что вызывает CLS и как это исправить?
  3. 03
    Google ранжирует страницы по полевым данным RUM, а не Lighthouse. Какое практическое значение это имеет?
Итог

Критический путь рендеринга браузера преобразует байты в пиксели через шесть этапов: разбор HTML, разбор CSS, построение дерева рендеринга, компоновка, отрисовка и композитинг. CSS блокирует рендеринг — ничего не отрисовывается до готовности CSSOM — делая его ресурсом с наивысшим приоритетом доставки. JavaScript без defer или async блокирует разбор HTML, задерживая всё. Preload scanner спасает, отправляя запросы подресурсов опережая основной парсер, но выводится из строя динамически внедрёнными URL. Core Web Vitals (LCP, INP, CLS) измеряют восприятие пользователем этого конвейера; Google использует полевые данные RUM (реальные пользователи Chrome), а не оценки Lighthouse для ранжирования. Четыре наиболее эффективных улучшения: CDN-кэш HTML (снизить TTFB), предзагрузить hero-изображение, отложить некритический JS и добавить размеры изображениям.

Связанные уроки
встречается в165
Продолжить восхождение ↑Перехват прокси и шлюзы безопасности: rate limiter, WAF, mTLS
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.