Lecture du DOM et performances

Grosses pertes de perfs ces jours-ci au boulot dans l'affichage d'un tableau d'environ 1200 cellules. Après comparaisons des récents commit, un suspect : la fonction calc en CSS. Ou plutôt la lecture de certaines propriétés d'élément DOM...

Petit cas de test tout simple : un bouton qui injecte dans le DOM 1200 éléments sur lesquels on applique une position en fonction de la taille de leur parent :

<!DOCTYPE html>
<html>
    <head>
        <title>CSS Calc benchmark</title>
        <meta charset="utf-8">
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
        <p><button type="button" id="calc">RUN</button></p>
        <div id="placeholder"></div>
        <script src="script.js"></script>
    </body>
</html>
Code HTML
.row {
    display: table-row;
    width: 100%;
}
.cell {
    display: table-cell;
    padding: 1rem;
    border: 1px solid #ccc;
}
.cell > * {
    position: relative;
}
Code CSS
const placeholder = document.getElementById('placeholder');
const run = function () {
    placeholder.innerHTML = '';
    let start = Date.now();
    for (let i = 0; i < 100;  i += 1) {
        let row = document.createElement('div');
        row.className = 'row';
        placeholder.appendChild(row);
        for (let j = 0; j < 12; j +=1) {
            let cell = document.createElement('span');
            cell.className = 'cell';
            row.appendChild(cell);
            let c = document.createElement('span');
            c.textContent = `${i}-${j}`;
            cell.appendChild(c);
            // position calculé
            c.style.top = `calc(50% - ${c.offsetHeight / 2}px`;
            // position fixe
            // c.style.top = '7px';
        }
    }
    console.log(Date.now() - start);
};
document.getElementById('calc').addEventListener('click', run);
Code javascript
Temps de rendu et comparaison.
Navigateurstop fixetop calculéRapport
chrome 64~ 5ms~ 360ms~ 70
Firefox 58~ 9ms~ 1800ms~ 200
edge 16~ 30ms~ 3600ms~ 120

La perte de performance est énorme sous Firfox mais il effectue le travail encore 2 fois plus vite que Edge qui traine la patte par rapport au 2 autres même quand on écrit une valeur fixe. Pour être précis, ce n'est pas calc qui pose problème ni même le fait d'appliquer la position mais bien d'aller lire le offsetHeight, source de reflow et donc coûteux en ressources.

Titre
What forces layout / reflow
Auteurs
  • Paul Irish
Éditeur
Github
Titre
Avoid Large, Complex Layouts and Layout Thrashing
Auteurs
  • Paul Lewis
Éditeur
developers.google.com