Performance CSS: минимизация repaint/reflow, оптимизация рендера
Почему браузер «тормозит»? Разбираем repaint и reflow
Браузер — не волшебник, а сложный механизм. Каждое изменение CSS заставляет его пересчитывать layout (reflow) или перерисовывать элементы (repaint). Чем чаще это происходит, тем медленнее работает страница.
Разница между reflow и repaint:
- Reflow (он же layout) — перерасчёт геометрии элементов. Например, изменили
width,marginили добавили DOM-узел. - Repaint — визуальное обновление без изменения layout. Пример:
color,background,visibility.
💡 Как запомнить? Reflow = «где?» (позиция, размер), Repaint = «как?» (цвет, тень).
Как минимизировать reflow?
1. Группируйте изменения DOM
Каждое добавление/удаление элемента вызывает reflow. Вместо этого:
// Плохо: 10 reflow!
for (let i = 0; i < 10; i++) {
document.body.appendChild(document.createElement('div'));
}
// Хорошо: 1 reflow!
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
fragment.appendChild(document.createElement('div'));
}
document.body.appendChild(fragment);
2. Избегайте «чтения» геометрии после «записи»
Браузер оптимизирует reflow, но только если вы не заставляете его возвращать актуальные значения. Пример:
// Плохо: вызывает принудительный reflow!
element.style.width = '100px';
const width = element.offsetWidth; // Чтение → браузер вынужден обновить layout
element.style.height = `${width}px`;
// Хорошо: сначала читаем, потом пишем
const width = element.offsetWidth;
element.style.width = '100px';
element.style.height = `${width}px`;
Оптимизируем repaint
1. Используйте transform и opacity
Эти свойства не вызывают reflow и обрабатываются отдельным слоем (composite). Анимация их через transition или animation — идеально!
.box {
transition: transform 0.3s ease; /* GPU-ускорение! */
}
.box:hover {
transform: scale(1.1); /* Никакого repaint! */
}
2. Осторожно с will-change
Подсказка браузеру о будущих изменениях:
.element {
will-change: transform; /* Готовимся к анимации */
}
⚠️ Не злоупотребляйте! Лишние слои (layers) съедают память.
CSS-свойства: от «тяжёлых» к «лёгким»
| Тяжёлые (reflow) | Средние (repaint) | Лёгкие (composite) |
|---|---|---|
width |
color |
transform |
margin |
background |
opacity |
padding |
box-shadow |
filter |
position |
outline |
clip-path |
Практика: оптимизация анимаций
Проблема: Анимация top/left вызывает reflow на каждом кадре.
Решение: Заменяем на transform: translate().
/* Плохо: прыгающий reflow */
@keyframes slide {
from { left: 0; }
to { left: 100px; }
}
/* Хорошо: плавно и без reflow */
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(100px); }
}
Итоги: чеклист оптимизации
- DOM: Изменяйте группами, используйте
DocumentFragment. - JavaScript: Читайте геометрию (например,
offsetHeight) перед записью. - Анимации:
transformиopacity— ваши лучшие друзья. - Слои:
will-change— только там, где действительно нужно. - Инструменты: Chrome DevTools → Performance → ищите «Layout Thrashing».
Теперь ваш CSS не просто красивый — он молниеносный! ⚡