Il layout thrashing (noto anche come layout sincrono forzato o forced reflow) si verifica quando JavaScript alterna ripetutamente scritture nel DOM e letture delle proprietà di layout, costringendo il browser a ricalcolare il layout in modo sincrono.
Trigger di Invalidazione del Layout
Le seguenti proprietà e metodi DOM forzano il ricalcolo sincrono della geometria ogni volta che il layout è stato invalidato da precedenti mutazioni.
Proprietà e Metodi degli Elementi
Geometria e Dimensioni Box
clientHeight,clientWidthclientLeft,clientTopoffsetHeight,offsetWidthoffsetLeft,offsetTopoffsetParentscrollHeight,scrollWidthscrollLeft,scrollTop
Interrogazione Bounding Box
getBoundingClientRect()getClientRects()
Azioni di Scorrimento
scrollIntoView()scrollIntoViewIfNeeded()scrollByLines()scrollByPages()
Testo e Focus
innerTextouterTextfocus()(forza anello di focus e aggiustamenti dello scorrimento)
Proprietà di MouseEvent
Interrogare determinate coordinate su un’istanza MouseEvent può innescare il calcolo del layout in alcuni motori di rendering:
layerX,layerYoffsetX,offsetY
Metodi e Proprietà di Window
window.getComputedStyle()(quando si interrogano valori dipendenti dal layout come width, height o margin)window.scrollBy()window.scrollTo()window.scrollX,window.scrollY
Frame, Documento e Immagine
- Interrogazione di
widthoheightsu un’immagine prima della stabilizzazione del layout - Accesso a
document.body.scrollHeight
Operazioni jQuery
Molti metodi helper di jQuery leggono internamente valori calcolati di layout:
// Innesca reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width'); // Qualsiasi calcolo di stile dipendente dal layout
$(elem).text();
// Pseudo-selettori che verificano la visibilità geometrica
$(':hidden');
$(':visible');
$(':contains');
Best Practice per Evitare il Layout Thrashing
1. Raggruppa Letture e Scritture
Esegui sempre prima tutte le misurazioni DOM, poi raggruppa tutte le modifiche insieme.
// MALE: Alternare letture e scritture forza il layout ad ogni iterazione
elements.forEach((el) => {
const width = el.clientWidth; // LETTURA (forza layout)
el.style.width = width * 2 + 'px'; // SCRITTURA (invalida layout)
});
// BENE: Prima letture in batch, poi scritture in batch
const widths = elements.map((el) => el.clientWidth); // LETTURA IN BATCH
elements.forEach((el, index) => {
el.style.width = widths[index] * 2 + 'px'; // SCRITTURA IN BATCH
});
2. Usa requestAnimationFrame
Pianifica le modifiche di stile nel frame di animazione successivo per ottimizzare il ciclo di rendering:
const height = element.clientHeight; // Leggi nella fase corrente
window.requestAnimationFrame(() => {
element.style.height = height + 50 + 'px'; // Scrivi nel frame successivo
});
3. Usa CSS Transforms e Opacity
Preferisci animare proprietà CSS gestite dal compositor thread (transform, opacity) rispetto a proprietà di layout (top, left, width, height).