\n \n\n```\n\n**Важно:**\n- CSS (в head) **блокирует** парсинг и отрисовку (CSSOM должен быть готов перед отрисовкой)\n- JS (в body) **блокирует** парсинг до выполнения\n\n### 2. CSS парсинг\n\nОдновременно с HTML браузер скачивает и парсит CSS, создавая **CSSOM (CSS Object Model)**.\n\nБраузер ждет, пока оба готовы: DOM + CSSOM → Render Tree\n\n### 3. Создание Render Tree\n\nRender Tree комбинирует DOM и CSSOM. Это визуальное представление страницы.\n\n```\nDOM: CSSOM: Render Tree:\n * { margin: 0 } html\n body { bg: white } ├─ body (visible)\n

Ок

h1 { color: red } │ ├─ h1 (visible)\n \n\n\n\n\n\n\n```\n\n**3. Минимизируй Layout (Reflow)**\n\n```javascript\n// ❌ 3 Reflow\nelement.style.width = '100px'\nconst height = element.offsetHeight // Reflow 1\nelement.style.height = '200px'\nconst width = element.offsetWidth // Reflow 2\nelement.style.margin = '10px'\nconsole.log(element.offsetTop) // Reflow 3\n\n// ✅ Кэшируй\nconst styles = {\n width: '100px',\n height: '200px',\n margin: '10px'\n}\nObject.assign(element.style, styles) // Один batch Layout\n```\n\n**4. Используй requestAnimationFrame**\n\n```javascript\n// ❌ Медленно\nfor (let i = 0; i < 100; i++) {\n elements[i].style.transform = `translateX(${i}px)`\n}\n\n// ✅ Оптимизировано\nrequestAnimationFrame(() => {\n for (let i = 0; i < 100; i++) {\n elements[i].style.transform = `translateX(${i}px)`\n }\n})\n```\n\n**5. Используй transform вместо position**\n\n```css\n/* ❌ Вызывает Layout + Paint */\n.box {\n position: absolute;\n left: 50px; /* Изменение left = Layout */\n}\n\n/* ✅ Только Composite (GPU) */\n.box {\n transform: translateX(50px); /* Быстро! */\n}\n```\n\n### Инструменты для анализа\n\n**Chrome DevTools Performance:**\n\n```\n1. Открыть DevTools (F12)\n2. Performance вкладка\n3. Нажать Record\n4. Выполнить действие\n5. Нажать Stop\n6. Смотреть временную шкалу: Parse → Style → Layout → Paint → Composite\n```\n\n**Идентификаторы в timeline:**\n- Фиолетовый: Парсинг\n- Зелёный: Rendering (Layout + Paint)\n- Жёлтый: JavaScript\n- Красный: Composite\n\n### Пример: анимация\n\n```javascript\n// ❌ Неправильно — вызывает Layout каждый кадр\nfunction animate() {\n for (let i = 0; i < 1000; i++) {\n elements[i].style.left = (Math.random() * 100) + 'px' // Layout!\n }\n requestAnimationFrame(animate)\n}\n\n// ✅ Правильно — используем transform\nfunction animate() {\n for (let i = 0; i < 1000; i++) {\n elements[i].style.transform = `translate(${Math.random() * 100}px, 0)` // Composite!\n }\n requestAnimationFrame(animate)\n}\n```\n\n### Вывод\n\n1. **Понимай процесс:** Parse → Style → Layout → Paint → Composite\n2. **Layout (Reflow) — самый дорогой** — избегай в циклах\n3. **Используй transform вместо position/size** для анимаций\n4. **Кэшируй значения свойств** (offsetWidth и т.д.)\n5. **Отложи CSS и JS** (async/defer)\n6. **Профилируй в DevTools Performance** для измерения\n\nЭта информация критична для создания высокопроизводительных приложений!","dateCreated":"2026-03-23T11:54:19.493009","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Как браузер отрисовывает страницу?

1.0 Junior🔥 171 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как браузер отрисовывает страницу?

Это один из самых важных вопросов для фронтендера. Понимание процесса отрисовки критично для оптимизации производительности. Браузер проходит через несколько четких этапов: парсинг, стилизация, компоновка, отрисовка и композиция.

Основные этапы (Critical Rendering Path)

1. HTML парсинг
   ↓
2. CSS парсинг
   ↓
3. DOM + CSSOM → Render Tree
   ↓
4. Layout (Reflow)
   ↓
5. Paint (Repaint)
   ↓
6. Composite (Композиция)

1. HTML парсинг

Браузер скачивает HTML и парсит его снизу вверх (зверху вниз), создавая DOM (Document Object Model).

<!DOCTYPE html>
<html>
  <head>
    <title>Моя страница</title>
    <link rel="stylesheet" href="style.css"> <!-- Блокирует парсинг -->
  </head>
  <body>
    <h1>Заголовок</h1>
    <p>Текст</p>
    <script src="app.js"></script> <!-- Блокирует парсинг -->
  </body>
</html>

Важно:

  • CSS (в head) блокирует парсинг и отрисовку (CSSOM должен быть готов перед отрисовкой)
  • JS (в body) блокирует парсинг до выполнения

2. CSS парсинг

Одновременно с HTML браузер скачивает и парсит CSS, создавая CSSOM (CSS Object Model).

Браузер ждет, пока оба готовы: DOM + CSSOM → Render Tree

3. Создание Render Tree

Render Tree комбинирует DOM и CSSOM. Это визуальное представление страницы.

DOM:                CSSOM:              Render Tree:
<html>              * { margin: 0 }     html
  <body>            body { bg: white }    ├─ body (visible)
    <h1>Ок</h1>     h1 { color: red }    │  ├─ h1 (visible)
    <script>        script { ... }       │  └─ p (visible)
    <p>Текст</p>                        └─ script (hidden)

Важно: Элементы с display: none НЕ в Render Tree. Элементы с visibility: hidden есть в Render Tree, но не отрисовываются.

4. Layout (Reflow)

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

// Просмотр размеров
const box = document.querySelector('.box')
console.log(box.offsetWidth)   // Читаем размер
console.log(box.offsetHeight)  // Это запускает Layout!
console.log(box.getBoundingClientRect())  // И это тоже!

Что вызывает Layout (Reflow):

  • Изменение width, height, margin, padding
  • Изменение display, position
  • Прочтение offsetWidth, offsetHeight, scrollHeight и т.д.
  • Изменение window size

Layout стоит дорого — требует пересчета позиций всех элементов. Нужно избегать его в циклах:

// ❌ ПЛОХО — Layout в каждой итерации
for (let i = 0; i < 1000; i++) {
  const height = elements[i].offsetHeight  // Layout каждый раз
  elements[i].style.width = height + 'px'  // И еще Layout
}

// ✅ ХОРОШО — кэшируй значения
const heights = Array.from(elements).map(el => el.offsetHeight)  // Один Layout
heights.forEach((height, i) => {
  elements[i].style.width = height + 'px'
})

5. Paint (Repaint)

Браузер рисует пиксели на экране: цвета, тени, границы и т.д.

// Что вызывает Paint (Repaint):
// - Изменение color, background-color
// - Изменение box-shadow
// - Изменение border-radius
// - Любое визуальное изменение (кроме layout)

element.style.color = 'red'  // Paint
element.style.backgroundColor = 'blue'  // Paint

Paint стоит дорого (но дешевле Layout). Старайся избегать частых перекрасок.

6. Composite (Композиция)

Браузер объединяет слои (layer) в финальное изображение.

Certain CSS свойства создают новый слой (composition layer):

  • transform
  • opacity
  • will-change
  • filter
  • position: fixed
.box {
  transform: translateX(50px);  /* Композиция, НЕ Layout */
  /* Работает с GPU, очень быстро */
}

.box:hover {
  left: 50px;  /* Layout + Paint, медленнее */
}

Визуальная схема

         ┌─────────────────────────────┐
         │    JavaScript выполняется    │
         └────────────┬────────────────┘
                      ↓
         ┌─────────────────────────────┐
         │    Парсинг (Parse)          │
         │  DOM, CSSOM создаются       │
         └────────────┬────────────────┘
                      ↓
         ┌─────────────────────────────┐
         │  Style calculations         │
         │  (какие стили применять)    │
         └────────────┬────────────────┘
                      ↓
         ┌─────────────────────────────┐
         │   Layout (Reflow)           │
         │  Размеры и позиции          │
         └────────────┬────────────────┘
                      ↓
         ┌─────────────────────────────┐
         │   Paint (Repaint)           │
         │  Рисуем пиксели             │
         └────────────┬────────────────┘
                      ↓
         ┌─────────────────────────────┐
         │   Composite                 │
         │  Объединяем слои            │
         └─────────────────────────────┘

Пример: жизненный цикл изменения

const box = document.querySelector('.box')

// 1. JavaScript выполняется
box.style.width = '200px'  // Отмечаем, что нужен Layout
box.style.backgroundColor = 'red'  // Отмечаем Paint

// 2. Браузер выполняет Reflow (Layout)
// 3. Браузер выполняет Repaint
// 4. Браузер выполняет Composite

// Если запросим размер, браузер СРАЗУ выполнит Layout
const width = box.offsetWidth  // Layout случается ТУТ!

Оптимизация: Critical Rendering Path

1. Уменьши CSS (блокирует парсинг)

<!-- ❌ Медленно -->
<link rel="stylesheet" href="styles-100kb.css">

<!-- ✅ Быстро -->
<link rel="stylesheet" href="critical.css">
<link rel="stylesheet" href="rest.css" media="print">  <!-- Асинхронно -->

2. Отложи JavaScript

<!-- ❌ Блокирует парсинг -->
<script src="app.js"></script>

<!-- ✅ Асинхронно -->
<script async src="app.js"></script>

<!-- ✅ После парсинга -->
<script defer src="app.js"></script>

3. Минимизируй Layout (Reflow)

// ❌ 3 Reflow
element.style.width = '100px'
const height = element.offsetHeight  // Reflow 1
element.style.height = '200px'
const width = element.offsetWidth  // Reflow 2
element.style.margin = '10px'
console.log(element.offsetTop)  // Reflow 3

// ✅ Кэшируй
const styles = {
  width: '100px',
  height: '200px',
  margin: '10px'
}
Object.assign(element.style, styles)  // Один batch Layout

4. Используй requestAnimationFrame

// ❌ Медленно
for (let i = 0; i < 100; i++) {
  elements[i].style.transform = `translateX(${i}px)`
}

// ✅ Оптимизировано
requestAnimationFrame(() => {
  for (let i = 0; i < 100; i++) {
    elements[i].style.transform = `translateX(${i}px)`
  }
})

5. Используй transform вместо position

/* ❌ Вызывает Layout + Paint */
.box {
  position: absolute;
  left: 50px;  /* Изменение left = Layout */
}

/* ✅ Только Composite (GPU) */
.box {
  transform: translateX(50px);  /* Быстро! */
}

Инструменты для анализа

Chrome DevTools Performance:

1. Открыть DevTools (F12)
2. Performance вкладка
3. Нажать Record
4. Выполнить действие
5. Нажать Stop
6. Смотреть временную шкалу: Parse → Style → Layout → Paint → Composite

Идентификаторы в timeline:

  • Фиолетовый: Парсинг
  • Зелёный: Rendering (Layout + Paint)
  • Жёлтый: JavaScript
  • Красный: Composite

Пример: анимация

// ❌ Неправильно — вызывает Layout каждый кадр
function animate() {
  for (let i = 0; i < 1000; i++) {
    elements[i].style.left = (Math.random() * 100) + 'px'  // Layout!
  }
  requestAnimationFrame(animate)
}

// ✅ Правильно — используем transform
function animate() {
  for (let i = 0; i < 1000; i++) {
    elements[i].style.transform = `translate(${Math.random() * 100}px, 0)`  // Composite!
  }
  requestAnimationFrame(animate)
}

Вывод

  1. Понимай процесс: Parse → Style → Layout → Paint → Composite
  2. Layout (Reflow) — самый дорогой — избегай в циклах
  3. Используй transform вместо position/size для анимаций
  4. Кэшируй значения свойств (offsetWidth и т.д.)
  5. Отложи CSS и JS (async/defer)
  6. Профилируй в DevTools Performance для измерения

Эта информация критична для создания высокопроизводительных приложений!

Как браузер отрисовывает страницу? | PrepBro