Разбираемся с Render Tree: Layout, Paint, Composite

Frontend

На интервью иногда спрашивают о том, что происходит между тем, как браузер получил HTML-код, и тем, как вы увидели готовую страницу. Сегодня разберем Render Tree — одно из важных понятий в работе браузера. Если не разобраться с этим, то о понимании тем производительности, критических метрик и оптимизации загрузки можно и не мечтать.

Если сказать совсем просто, то Render Tree — это про то, что браузер не рендерит всё подряд. Он сначала строит оптимизированную версию документа, содержащую только те элементы, которые реально появятся на экране. Это и есть Render Tree.

Что такое Render Tree простыми словами

Render Tree (дерево рендеринга) — это структура данных, которую браузер строит из DOM и CSSOM. Она содержит только видимые элементы, которые будут отображены на экране, и их вычисленные стили.

Процесс выглядит так:

Разбираем HTML → Получаем DOM
Разбираем CSS  → Получаем CSSOM
Совмещаем DOM и CSSOM → Получаем Render Tree и выполняем отрисовку по стадиям
	→ Layout
	→ Paint
	→ Composite

Как строится Render Tree

Шаг 1. Обход DOM сверху вниз

Браузер начинает с корневого элемента <html> и обходит всех потомков.

Шаг 2. Отсев невидимых элементов

Браузер исключает:

  • <head> и всё его содержимое (теги <title><meta><link><script>).
  • Элементы с display: none (они не занимают места и не отрисовываются).
  • Элементы с visibility: hidden (они остаются в Render Tree, так как занимают место, но невидимы).
  • Псевдоэлементы (::before::after) — они добавляются в Render Tree, только если есть контент.
  • Элементы вне потока (если они невидимы).

Шаг 3. Применение стилей (сопоставление с CSSOM)

Браузер вычисляет итоговые стили для каждого оставшегося элемента (тут то и применяются каскадность, наследование, специфичность CSS). Так получается называется Computed Style.

Шаг 4. Создание дерева

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

Как выглядит Render Tree (пример)

HTML

<!DOCTYPE html>
<html>
<head>
    <style>
        .hidden { display: none; }
        .invisible { visibility: hidden; }
    </style>
</head>
<body>
    <h1>Заголовок</h1>
    <p>Абзац текста</p>
    <div class="hidden">Я не попаду в Render Tree</div>
    <div class="invisible">Я попаду, но буду невидим</div>
    <img src="photo.jpg" alt="Фото">
</body>
</html>

Render Tree (упрощенно)

root (body)
├── h1: { font-size: 2em; color: black; }
├── p: { font-size: 1em; color: black; }
├── div.invisible: { visibility: hidden; display: block; }
└── img: { width: 100px; height: 100px; }

Что отсутствует:

  • <head> и его содержимое
  • <div class="hidden"> (display: none)

Что присутствует, но не видно:

  • <div class="invisible"> (visibility: hidden — занимает место)

Что происходит после построения Render Tree

После подготовки Render Tree, браузер выполняет несколько последовательных операций.

1. Layout — расчет геометрии

Браузер вычисляет точные размеры и позиции каждого узла в Render Tree.

Каждый элемент получает:
- width, height
- x, y (position)
- margin, padding, border

2. Paint — отрисовка пикселей

Браузер превращает каждый узел с его стилями в пиксели на экране. Рисует фон, текст, границы, тени.

3. Composite — наложение слоев

Если используются слои (например, will-change: transform), браузер объединяет их в финальное изображение.

Render Tree и производительность

1. Чем меньше Render Tree, тем быстрее рендеринг

Если в DOM 1000 элементов, но 500 из них скрыты (display: none), то в Render Tree попадет только 500. Меньше узлов = быстрее Layout и Paint.

Не удаляйте элементы из DOM, если они не нужны сразу — просто прячьте их до момента, когда они реально понадобятся.

2. Изменения Layout (рефлоу) стоят дорого

Любое изменение стилей может вызвать перестройку Render Tree и повторный Layout. А заним автоматически будут выполнены Paint и Composite. При этом если будет проведена рекомпозиция, то репейт и рефлоу не потребуются. Ну и репейнт приведет только к рекомпозиции, но не стриггерит рефлоу.

Что вызывает рефлоу:

  • Изменение размеров элементов (width, height)
  • Добавление/удаление элементов
  • Изменение display с none на block
  • Изменение шрифтов

Что НЕ вызывает рефлоу (только repaint):

  • Изменение цвета
  • Изменение visibility
  • Изменение opacity

3. Используйте will-change

.element {
    will-change: transform; /* создает отдельный слой */
}

Браузер выделяет такой элемент в отдельный слой (Render Layer), что ускоряет работу с анимациями и трансформациями.

Итого

  • Render Tree — это финальное дерево видимых элементов с вычисленными стилями. Его строит браузер перед отрисовкой.
  • В Render Tree не попадают элементы с display: none, содержимое <head>, скрытые элементы без места.
  • После построения Render Tree браузер делает Layout (расчет размеров/позиций), Paint (отрисовка пикселей) и Composite (совмещение слоев рендеринга).
  • Избегайте частых изменений стилей, которые вызывают перестройку Render Tree.

Render Tree — забота браузера, но понимание того, как это дерево строится, поможет вам писать более производительные приложения. Оптимизируйте DOM, не злоупотребляйте свойствами, влияющими на Layout, используйте слои для сложных анимаций.

Желаю успехов!

Симо Мофин
Симо Мофин

Senior Frontend Developer
Главный по блогу