Reflow (или layout) — процесс, при котором браузер пересчитывает геометрию элементов на странице: их размеры, положение, отступы, размеры контейнеров и т.д. Любое изменение, влияющее на layout, может вызвать reflow. Это одна из самых затратных операций по производительности, особенно на страницах с большим количеством элементов.
Repaint — процесс, при котором браузер перерисовывает элементы на экране после изменения их визуальных свойств, не затрагивающих layout, таких как цвет, фон, границы, тени. Repaint обычно менее затратен, чем reflow, но частые и крупные repaint также могут вызывать лаги и торможения интерфейса.
Reflow вызывают следующие действия:
width,
height, padding, border,
margin).display: none →
display: block).Repaint возникает при изменении свойств, влияющих только на визуальное отображение, но не на размеры:
color,
background-color).outline).box-shadow, text-shadow).opacity).Важно понимать, что reflow всегда вызывает repaint, но repaint может происходить без reflow.
Библиотека Bliss.js предоставляет удобные методы для работы с DOM, событиями и стилями, что позволяет оптимизировать частоту и масштаб изменений, вызывающих перерисовку страницы.
html()
и text()Методы html() и text() в Bliss.js позволяют
однократно обновлять содержимое элемента, что
минимизирует количество обращений к DOM. Вместо многократных манипуляций
с innerHTML:
// Плохо: несколько reflow
document.querySelector('#content').innerHTML = 'Первый блок';
document.querySelector('#content').innerHTML += 'Второй блок';
// Хорошо: один reflow
Bliss.$('#content').html('Первый блокВторой блок');
addClass и
removeClassИзменение стилей через класс предпочтительнее прямого присвоения стилей, так как браузер может оптимизировать перерисовку и применять batch-обновления:
let el = Bliss.$('#box');
el.addClass('active'); // Один reflow для всех стилей
el.removeClass('inactive');
each и mapЕсли нужно изменить несколько элементов, лучше использовать методы
each или map, чтобы выполнять изменения в
цикле внутри одного обхода коллекции:
Bliss.$$('.item').each(el => {
el.style.width = '200px';
el.style.backgroundColor = '#f0f0f0';
});
При необходимости добавить множество элементов в DOM, создание их
внутри DocumentFragment позволяет производить
только один reflow при вставке фрагмента:
let fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
let div = document.createElement('div');
div.textContent = `Элемент ${i}`;
fragment.appendChild(div);
}
Bliss.$('#container')[0].appendChild(fragment);
При изменении стилей, которые вызывают reflow, полезно временно
скрыть элемент (display: none), выполнить изменения, а
затем показать. Это предотвращает многократные пересчеты:
let el = Bliss.$('#menu');
el.css('display', 'none');
el.css('width', '300px');
el.css('height', '150px');
el.css('display', 'block');
requestAnimationFrame для визуальных
обновленийЧастые анимации или динамическое изменение DOM лучше привязывать к
requestAnimationFrame, чтобы браузер сам планировал
оптимальные моменты перерисовки:
function animateBox() {
Bliss.$('#box').css('left', '+=5px');
requestAnimationFrame(animateBox);
}
requestAnimationFrame(animateBox);
Частое чередование чтения и записи стилей (offsetWidth,
clientHeight, style.width) приводит к forced
reflow. Bliss.js позволяет кэшировать выборки:
let el = Bliss.$('#box');
let width = el[0].offsetWidth; // Чтение один раз
el.css('width', width + 50 + 'px'); // Запись
Соблюдение этого принципа позволяет избежать лишних перерисовок.
style.DocumentFragment и методы Bliss.js для
пакетной вставки элементов.requestAnimationFrame, а не
setTimeout или setInterval.Эффективное применение этих техник снижает нагрузку на браузер, ускоряет рендеринг страницы и делает интерфейс отзывчивым даже при большом количестве элементов и динамических обновлениях.