Le layout thrashing (ou mise en page synchrone forcée / reflow forcé) survient lorsque JavaScript alterne sans cesse entre l’écriture dans le DOM et la lecture de propriétés de géométrie, obligeant le navigateur à recalculer la mise en page de façon synchrone.
Déclencheurs d’invalidation du layout
Les propriétés et méthodes DOM suivantes forcent le recalcul synchrone de la géométrie dès que la mise en page a été invalidée par des mutations DOM antérieures.
Propriétés et méthodes des éléments
Géométrie et dimensions de boîte
clientHeight,clientWidthclientLeft,clientTopoffsetHeight,offsetWidthoffsetLeft,offsetTopoffsetParentscrollHeight,scrollWidthscrollLeft,scrollTop
Requête de boîtes englobantes
getBoundingClientRect()getClientRects()
Actions de défilement
scrollIntoView()scrollIntoViewIfNeeded()scrollByLines()scrollByPages()
Texte et focus
innerTextouterTextfocus()(force l’anneau de focus et les ajustements de défilement)
Propriétés d’événement souris
Interroger certaines coordonnées sur un objet MouseEvent peut déclencher un calcul de mise en page selon le moteur :
layerX,layerYoffsetX,offsetY
Méthodes et propriétés Window
window.getComputedStyle()(lors de la lecture de valeurs dépendant de la mise en page telles que largeur, hauteur ou marges)window.scrollBy()window.scrollTo()window.scrollX,window.scrollY
Frame, document et image
- Lecture de
widthouheightsur une image avant stabilisation du layout - Accès à
document.body.scrollHeight
Opérations jQuery
De nombreuses méthodes utilitaires jQuery lisent en interne les dimensions calculées :
// Déclenche un reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width'); // Tout calcul de style dépendant de la mise en page
$(elem).text();
// Pseudo-sélecteurs inspectant la visibilité géométrique
$(':hidden');
$(':visible');
$(':contains');
Bonnes pratiques contre le Layout Thrashing
1. Regrouper lectures et écritures par lots
Effectuez toujours toutes les mesures DOM d’abord, puis regroupez toutes les modifications DOM ensemble.
// À ÉVITER : Entrelacer lecture et écriture force un recalcul à chaque itération
elements.forEach((el) => {
const width = el.clientWidth; // LECTURE (force le layout)
el.style.width = width * 2 + 'px'; // ÉCRITURE (invalide le layout)
});
// RECOMMANDÉ : Lectures groupées, puis écritures groupées
const widths = elements.map((el) => el.clientWidth); // LECTURE GROUPÉE
elements.forEach((el, index) => {
el.style.width = widths[index] * 2 + 'px'; // ÉCRITURE GROUPÉE
});
2. Utiliser requestAnimationFrame
Planifiez les écritures de style dans la prochaine image d’animation afin d’optimiser le cycle de rendu :
const height = element.clientHeight; // Lecture durant la phase courante
window.requestAnimationFrame(() => {
element.style.height = height + 50 + 'px'; // Écriture dans l’image suivante
});
3. Utiliser CSS Transforms et Opacity
Privilégiez l’animation des propriétés CSS gérées sur le fil de composition (transform, opacity) plutôt que des propriétés de mise en page (top, left, width, height).