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

Будет ли вызван Reflow при изменении высоты и ширины элемента?

2.0 Middle🔥 201 комментариев
#HTML и CSS#Браузер и сетевые технологии

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Будет ли вызван Reflow при изменении высоты и ширины элемента?

Ответ: ДА, Reflow будет вызван при изменении высоты и ширины элемента.

Высота и ширина — это ключевые параметры макета (layout), поэтому их изменение обязательно пересчитает макет всей страницы или части её.

Что такое Reflow?

Reflow (перекомпоновка) — это процесс браузера, во время которого:

  1. Браузер пересчитывает позицию и размер каждого элемента
  2. Обновляет "box model" (отступы, границы, содержимое)
  3. Проверяет влияние изменений на другие элементы
  4. Может вызвать каскадное обновление соседних элементов

Это дорогая операция, которая блокирует рендеринг.

Какие свойства CSS вызывают Reflow?

// ДА, эти свойства вызывают REFLOW:
element.style.width = '200px';      // Изменение ширины
element.style.height = '100px';     // Изменение высоты
element.style.padding = '10px';     // Изменение отступов
element.style.margin = '5px';       // Изменение внешних отступов
element.style.top = '50px';         // Изменение позиции
element.style.left = '10px';        // Изменение позиции
element.style.display = 'block';    // Изменение отображения
element.style.position = 'relative';// Изменение позиционирования
element.style.fontSize = '14px';    // Изменение размера шрифта
element.style.fontWeight = 'bold';  // Влияет на ширину текста
element.textContent = 'New text';   // Изменение контента
element.appendChild(newChild);      // Добавление элемента
element.removeChild(child);         // Удаление элемента

// НЕТ, эти свойства вызывают только REPAINT:
element.style.color = 'red';        // Только цвет текста
element.style.backgroundColor = '#fff'; // Только фон
element.style.opacity = '0.5';      // Прозрачность (иногда оптимизируется)
element.style.boxShadow = '0 0 5px'; // Тень (может оптимизироваться)

Разница: Reflow vs Repaint

// REPAINT - обновляет только визуальное отображение
// Не влияет на макет
const element = document.querySelector('div');
element.style.color = 'red';        // Только перекрашивание
element.style.backgroundColor = 'blue'; // Только перекрашивание
element.style.opacity = '0.5';      // Только перекрашивание

// REFLOW - пересчитывает весь макет
// Гораздо медленнее
element.style.width = '200px';      // Reflow!
element.style.height = '100px';     // Reflow!

Визуально:

Reflow (дорого):   Parse HTML -> Recalculate Layout -> Paint -> Composite
Repaint (дешево):   Paint -> Composite

Пример: множественные Reflow

// ПЛОХО: 10 Reflow!
const element = document.querySelector('div');

element.style.width = '100px';  // Reflow #1
element.style.height = '100px'; // Reflow #2
element.style.padding = '10px'; // Reflow #3
element.style.margin = '5px';   // Reflow #4
element.style.border = '1px solid'; // Reflow #5
element.style.top = '20px';     // Reflow #6
// ... итого 6+ Reflow

// ХОРОШО: 1 Reflow!
element.style.cssText = `
  width: 100px;
  height: 100px;
  padding: 10px;
  margin: 5px;
  border: 1px solid;
  top: 20px;
`;
// cssText применяется одним Reflow!

// ХОРОШО: 1 Reflow с classList
element.classList.add('my-style'); // 1 Reflow
// CSS класс:
// .my-style {
//   width: 100px;
//   height: 100px;
//   padding: 10px;
// }

Практический пример: анимация без Reflow

// ПЛОХО: Reflow на каждый фрейм анимации
function animateBadly() {
  let position = 0;
  
  const interval = setInterval(() => {
    position += 10;
    element.style.left = position + 'px'; // Reflow каждый фрейм!
    
    if (position > 500) clearInterval(interval);
  }, 16); // 60fps
}

// ХОРОШО: используем CSS animations
function animateGood() {
  element.style.animation = 'slideRight 2s ease-in-out';
}

// CSS:
// @keyframes slideRight {
//   from { left: 0; }
//   to { left: 500px; }
// }
// Браузер оптимизирует анимацию!

// ОЧЕНЬ ХОРОШО: используем transform (оптимизировано на GPU)
function animateBest() {
  element.style.animation = 'slideRight 2s ease-in-out';
}

// CSS:
// @keyframes slideRight {
//   from { transform: translateX(0); }
//   to { transform: translateX(500px); }
// }
// transform НЕ вызывает Reflow!

Чтение свойств тоже может вызвать Reflow!

// ЛОВУШКА: Чтение вызывает Reflow перед вычислением
const width = element.offsetWidth;  // Чтение могут вызвать Reflow
const height = element.offsetHeight;
const top = element.offsetTop;

// Потому что браузер должен обновить layout перед возвратом значения

// Данные свойства ПРИЧИНЫ Reflow при чтении:
element.offsetHeight
element.offsetWidth
element.offsetTop
element.offsetLeft
element.scrollHeight
element.scrollWidth
element.scrollTop
element.scrollLeft
element.clientHeight
element.clientWidth
element.getComputedStyle() // Очень дорого!
window.getComputedStyle(element)

Оптимизация: избежать множественных Reflow

// ПЛОХО: множественные Reflow
const elements = document.querySelectorAll('.item');
elements.forEach(el => {
  el.style.width = el.offsetWidth * 1.5 + 'px'; // Читаем + пишем = 2 Reflow
});
// Итого: N * 2 Reflow

// ХОРОШО: сначала читаем, потом пишем
const widths = Array.from(elements).map(el => el.offsetWidth); // N Reflow
elements.forEach((el, i) => {
  el.style.width = widths[i] * 1.5 + 'px'; // N Reflow
});
// Итого: 2 больших Reflow вместо 2N маленьких

// ЛУЧШЕ: использовать DocumentFragment или скрыть элемент
const fragment = document.createDocumentFragment();
elements.forEach((el, i) => {
  const newEl = el.cloneNode(true);
  newEl.style.width = widths[i] * 1.5 + 'px';
  fragment.appendChild(newEl);
});
const parent = elements[0].parentNode;
parent.innerHTML = '';
parent.appendChild(fragment); // Один Reflow!

Реальный пример: изменение высоты в React

function ResizeableBox({ initialHeight = 200 }) {
  const [height, setHeight] = useState(initialHeight);
  const ref = useRef<HTMLDivElement>(null);
  
  const handleResize = () => {
    // ПЛОХО: Reflow в каждом фрейме
    setHeight(height + 10);
  };
  
  // ХОРОШО: использовать CSS transitions
  useEffect(() => {
    if (ref.current) {
      // Один Reflow при монтировании
      ref.current.style.transition = 'height 0.3s ease';
    }
  }, []);
  
  return (
    <div
      ref={ref}
      style={{
        height: `${height}px`,
        // Добавляем transition через CSS класс
        transition: 'height 0.3s ease'
      }}
    >
      Content
    </div>
  );
}

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

// Chrome DevTools Performance tab:
// 1. Открыть DevTools (F12)
// 2. Перейти в Performance tab
// 3. Нажать Record
// 4. Выполнить операцию
// 5. Нажать Stop
// 6. Смотреть Layout events в timeline

// Или programmatically:
performance.mark('reflow-start');
element.style.width = '100px';
performance.mark('reflow-end');
performance.measure('reflow', 'reflow-start', 'reflow-end');

const measure = performance.getEntriesByName('reflow')[0];
console.log(`Reflow took ${measure.duration}ms`);

Итоговая таблица

ОперацияReflowRepaintОптимизирована
width/height изменениеДаДаНет
color изменениеНетДаДа
transform изменениеНетНетДа (GPU)
opacity изменениеНетДа*Зависит
position изменениеДаДаНет
padding/marginДаДаНет
display изменениеДаДаНет
visibility: hiddenНетДа-
animation с transformНетНетДа
animation с left/topДаДаНет

Вывод

Изменение width и height ОБЯЗАТЕЛЬНО вызывает Reflow, потому что:

  • Это параметры макета
  • Влияют на расчёт размеров других элементов
  • Требуют пересчёта позиций и размеров

Для оптимизации:

  • Используй transform вместо left/top
  • Группируй изменения CSS через cssText или классы
  • Избегай чтения offsetWidth/offsetHeight в циклах
  • Используй CSS анимации вместо JavaScript
  • Профилируй с помощью DevTools Performance