Layout thrashing (cunoscut și ca layout sincron forțat sau forced reflow) apare atunci când codul JavaScript alternează repetat între scrierea în DOM și citirea proprietăților geometrice, forțând browserul să recalculeze sincron aspectul paginii.
Declanșatori de Invalidare a Layout-ului
Următoarele proprietăți și metode DOM forțează recalcularea sincronă a geometriei ori de câte ori layout-ul a fost invalidat de mutații DOM anterioare.
Proprietăți și Metode ale Elementelor
Geometria și Dimensiunile Cutiei
clientHeight,clientWidthclientLeft,clientTopoffsetHeight,offsetWidthoffsetLeft,offsetTopoffsetParentscrollHeight,scrollWidthscrollLeft,scrollTop
Interogări Bounding Box
getBoundingClientRect()getClientRects()
Acțiuni de Derulare
scrollIntoView()scrollIntoViewIfNeeded()scrollByLines()scrollByPages()
Text și Focus
innerTextouterTextfocus()(forțează ajustări ale inelului de focus și derulării)
Proprietăți ale Evenimentelor Mouse
Interogarea anumitor coordonate pe o instanță MouseEvent poate declanșa calcularea layout-ului în unele motoare de browser:
layerX,layerYoffsetX,offsetY
Metode și Proprietăți Window
window.getComputedStyle()(când se interoghează valori dependente de layout precum lățime, înălțime sau margini)window.scrollBy()window.scrollTo()window.scrollX,window.scrollY
Frame, Document și Imagine
- Interogarea
widthsauheightpe o imagine înainte ca layout-ul să se stabilizeze - Accesarea
document.body.scrollHeight
Operațiuni jQuery
Multe metode ajutătoare jQuery citesc intern valori de layout calculate:
// Declanșează reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width'); // Orice calcul de stil dependent de layout
$(elem).text();
// Pseudo-selectori care verifică vizibilitatea geometrică
$(':hidden');
$(':visible');
$(':contains');
Bune Practici pentru a Preveni Layout Thrashing
1. Grupează Citirile și Scrierile
Efectuează întotdeauna mai întâi toate măsurătorile DOM, apoi grupează împreună toate modificările DOM.
// GREȘIT: Alternarea citirii și scrierii forțează layout-ul la fiecare iterație
elements.forEach((el) => {
const width = el.clientWidth; // CITIRE (forțează layout)
el.style.width = width * 2 + 'px'; // SCRIERE (invalidează layout)
});
// CORECT: Citiri în lot, apoi scrieri în lot
const widths = elements.map((el) => el.clientWidth); // CITIRE ÎN LOT
elements.forEach((el, index) => {
el.style.width = widths[index] * 2 + 'px'; // SCRIERE ÎN LOT
});
2. Folosește requestAnimationFrame
Programează scrierile de stil în următorul cadru de animație pentru a lăsa browserul să optimizeze ciclul de randare:
const height = element.clientHeight; // Citește în faza curentă
window.requestAnimationFrame(() => {
element.style.height = height + 50 + 'px'; // Scrie în cadrul următor
});
3. Folosește CSS Transforms și Opacity
Preferă animarea proprietăților CSS gestionate pe firul compositorului (transform, opacity) în locul proprietăților de layout (top, left, width, height).