Краткий справочник

Шпаргалка по Layout Thrashing и принудительному Reflow

Подробный справочник по layout thrashing и принудительному reflow: свойства DOM, события мыши, методы window и вызовы jQuery, вызывающие перерасчёт макета.

· Опубликовано

Layout thrashing (также известный как принудительная синхронная компоновка или forced reflow) возникает, когда JavaScript многократно чередует запись в DOM и чтение геометрических свойств, заставляя браузер синхронно пересчитывать раскладку страницы.

Триггеры пересчёта компоновки (Layout Invalidation)

Перечисленные ниже свойства и методы DOM вызывают принудительный синхронный перерасчёт геометрии, если компоновка была сброшена предшествующими изменениями DOM.

Свойства и методы элементов

Геометрия и размеры блока

  • clientHeight, clientWidth
  • clientLeft, clientTop
  • offsetHeight, offsetWidth
  • offsetLeft, offsetTop
  • offsetParent
  • scrollHeight, scrollWidth
  • scrollLeft, scrollTop

Запрос ограничивающих прямоугольников

  • getBoundingClientRect()
  • getClientRects()

Операции прокрутки

  • scrollIntoView()
  • scrollIntoViewIfNeeded()
  • scrollByLines()
  • scrollByPages()

Текст и фокус

  • innerText
  • outerText
  • focus() (вызывает пересчёт рамки фокуса и прокрутки)

Свойства событий мыши

Чтение некоторых координат у объекта MouseEvent в ряде движков браузера может запускать перерасчёт компоновки:

  • layerX, layerY
  • offsetX, offsetY

Методы и свойства Window

  • window.getComputedStyle() (при запросе зависящих от раскладки значений: ширины, высоты, отступов, трансформаций)
  • window.scrollBy()
  • window.scrollTo()
  • window.scrollX, window.scrollY

Фреймы, документ и изображения

  • Чтение width или height изображения до стабилизации раскладки
  • Обращение к document.body.scrollHeight

Операции jQuery

Многие вспомогательные методы jQuery под капотом запрашивают вычисленные параметры компоновки:

// Вызывает reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width');  // Любое вычисление стилей, зависящее от компоновки
$(elem).text();

// Псевдоселекторы, проверяющие геометрическую видимость
$(':hidden');
$(':visible');
$(':contains');

Лучшие практики предотвращения Layout Thrashing

1. Пакетное чтение и пакетная запись

Сначала выполните все измерения в DOM, а затем сгруппируйте все изменения DOM вместе.

// ПЛОХО: чередование чтения и записи вызывает перерасчёт на каждой итерации
elements.forEach((el) => {
  const width = el.clientWidth; // ЧТЕНИЕ (принудительный layout)
  el.style.width = width * 2 + 'px'; // ЗАПИСЬ (инвалидация layout)
});

// ХОРОШО: сначала пакетное чтение, затем пакетная запись
const widths = elements.map((el) => el.clientWidth); // ПАКЕТНОЕ ЧТЕНИЕ
elements.forEach((el, index) => {
  el.style.width = widths[index] * 2 + 'px'; // ПАКЕТНАЯ ЗАПИСЬ
});

2. Используйте requestAnimationFrame

Планируйте обновление стилей на следующий кадр анимации, чтобы браузер оптимизировал цикл рендеринга:

const height = element.clientHeight; // Чтение в текущей фазе

window.requestAnimationFrame(() => {
  element.style.height = height + 50 + 'px'; // Запись в следующем кадре
});

3. Используйте CSS Transforms и Opacity

Анимируйте свойства, обрабатываемые потоком композитора (transform, opacity), вместо свойств раскладки (top, left, width, height).


Ссылки

Связанные темы