← Назад к вопросам

Является ли repaint перерисовкой на основе данных пересчета стилей в reflow?

1.7 Middle🔥 221 комментариев
#Оптимизация и производительность

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

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

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

Взаимосвязь Reflow и Repaint: это не прямая зависимость

Нет, repaint (перерисовка) не является прямым следствием на основе данных, полученных исключительно из reflow (пересчёт макета). Это два отдельных, хотя и тесно связанных процесса в рендеринговом конвейере браузера. Правильнее сказать, что оба процесса могут быть запущены изменениями в DOM или стилях, а reflow часто, но не всегда влечёт за собой repaint.

Разберем процессы по отдельности

1. Reflow (Перекомпоновка / Пересчёт макета)

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

Типичные триггеры:

  • Изменение размеров, содержимого, шрифта элемента.
  • Добавление или удаление DOM-элементов.
  • Изменение CSS-свойств, влияющих на геометрию: width, height, padding, margin, position, float, display и многие другие.
  • Активные вычисления макета, например, получение offsetWidth, scrollTop, getComputedStyle() (может вызвать синхронный, или "принудительный", reflow).

Что происходит: Браузер проходит по части или по всему Render Tree (дереву рендеринга, объединяющему DOM и CSSOM) и заново вычисляет положение и размеры каждого элемента.

2. Repaint (Перерисовка)

Это процесс обновления пикселей на экране, когда изменения элементов влияют на их визуальное отображение, но не на макет.

Типичные триггеры:

  • Изменение чисто визуальных свойств: color, background-color, visibility, outline, border-color, box-shadow (не влияющее на размеры).
  • Важный нюанс: Repaint также автоматически происходит после завершения reflow, так как обновлённая геометрия элемента должна быть отрисована на экране.

Что происходит: Браузер проверяет области видимости (прямоугольники) элементов, которые изменились, и перерисовывает только эти пиксели на слоях (layers), финально композит которых и формирует кадр (frame).

Ключевая взаимосвязь и ход процессов

flowchart TD
    A[Изменение DOM/CSS] --> B{Тип изменения};
    B -->|Изменение геометрии<br>width, height, position и т.д.| C[Reflow<br>Пересчёт макета];
    B -->|Только визуальные свойства<br>color, background и т.д.| D[Repaint<br>Перерисовка];
    C --> E[Обновление Render Tree];
    E --> D;
    D --> F[Композиция слоёв];
    F --> G[Отображение кадра];

Главный вывод из схемы:

  • Reflow ВСЕГДА вызывает последующий Repaint, потому что если элемент сдвинулся или изменил размер, его новый вид нужно нарисовать.
  • Repaint МОЖЕТ происходить БЕЗ Reflow, если изменения чисто визуальные и не затрагивают геометрию или положение элемента в потоке документа.

Пример кода для иллюстрации

// Пример 1: Только REPAINT (более дешёвая операция)
const element1 = document.getElementById('myDiv');
element1.style.color = 'red';        // Меняется только цвет текста
element1.style.backgroundColor = '#eee'; // Меняется фон
// Затрагиваются только визуальные свойства, макет не меняется.
// Браузер пропускает стадию reflow, сразу выполняя repaint.

// Пример 2: REFLOW + REPAINT (дорогая операция)
const element2 = document.getElementById('myOtherDiv');
element2.style.width = '500px';     // Меняется геометрия элемента
element2.style.padding = '20px';    // Меняется геометрия элемента
// Эти изменения заставляют браузер:
// 1. Выполнить RECALCULATE STYLE (пересчёт стилей).
// 2. Выполнить REFLOW (пересчитать макет для этого элемента и, возможно, соседей).
// 3. Выполнить REPAINT (отрисовать результат).

// Пример 3: "Принудительный синхронный" REFLOW (ОЧЕНЬ дорогая операция)
// Неоптимальный код:
element2.style.width = '500px'; // Запускает асинхронную очередь на пересчёт
// Следующая строка ЗАСТАВЛЯЕТ браузер выполнить reflow СИНХРОННО,
// чтобы дать актуальное значение, ломая оптимизацию браузера:
const currentWidth = element2.offsetWidth; // Форсированный синхронный reflow!
element2.style.height = currentWidth + 'px'; // Снова изменение, снова reflow.
// За один кадр произошло два вынужденных reflow.

Оптимизация для разработчика

Понимание этой разницы критически важно для производительности:

  1. Минимизируйте триггеры reflow. Изменяйте визуальные свойства (opacity, transform) вместо геометрических, где это возможно. Свойства transform и opacity обрабатываются на этапе композиции, минуя и reflow, и repaint.
  2. Избегайте принудительных синхронных перерасчётов. Не читайте геометрические свойства (offsetTop, scrollLeft, getComputedStyle()) сразу после их изменения. Если это необходимо — сначала прочитать все нужные значения, затем произвести все записи (техника "чтение-запись" батчинг).
  3. Модифицируйте DOM оффлайн. Используйте DocumentFragment или клонируйте и изменяйте узлы, отключённые от DOM (display: none), а затем вставляйте их одним действием.

Таким образом, repaint — это более узкий и часто заключительный этап, который может, но не обязан запускаться данными из reflow. Задача frontend-разработчика — строить анимации и интерактивность так, чтобы по возможности запускать только repaint или этап композиции, полностью избегая дорогостоящих операций reflow.