Layout thrashing: багаторазові reflow в одному кадрі і як їх прибрати
Що відбувається
Браузер намагається перераховувати макет один раз за кадр. Але якщо код пише стиль, потім читає геометрію (offsetWidth, getBoundingClientRect), потім знову пише — у циклі — кожне читання примусово запускає свіжий синхронний перерахунок макета всієї сторінки. Цикл по 100 елементах може спричинити 100 повних reflow в одному кадрі.
Вартість пропорційна розміру DOM: код, нешкідливий на маленькій сторінці, убиває INP на сторінці з тисячами вузлів.
Як розпізнати
- Presentation delay (робота рендерингу після обробника) домінує в розбивці INP.
- У DevTools Performance всередині одного кадру видно багато фіолетових блоків Layout, часто з позначкою «Forced reflow».
- Код чергує читання (offsetTop, clientHeight, getComputedStyle) і записи (style, classList) усередині циклу.
Як виправити
- Згрупуйте спершу всі читання, потім усі записи — ніколи не чергуйте їх у циклі.
- Перенесіть записи в requestAnimationFrame, щоб вони потрапляли прямо перед наступним відмалюванням.
- Віддавайте перевагу CSS-рішенням (класи, transform, flex/grid) над вимірюванням і позиціюванням елементів у JS.
Проблема
items.forEach((el) => {
el.style.width = base + "px" // write
const h = el.offsetHeight // read → forced reflow, every iteration
el.style.height = h * 2 + "px" // write
})
Виправлення
const heights = items.map((el) => el.offsetHeight) // all reads
requestAnimationFrame(() => {
items.forEach((el, i) => { // all writes
el.style.width = base + "px"
el.style.height = heights[i] * 2 + "px"
})
})
Просканувати свій сайт безкоштовно →