Éviter les peintures inutiles

Introduction

Peindre les éléments d'un site ou d'une application peut être très coûteux et avoir un impact négatif sur les performances d'exécution. Dans cet article, nous examinons rapidement ce qui peut déclencher le dessin dans le navigateur et comment éviter les dessins inutiles.

Peinture : visite guidée très rapide

L'une des tâches principales d'un navigateur consiste à convertir votre DOM et votre CSS en pixels à l'écran. Il s'agit d'un processus assez complexe. Il commence par lire le balisage, puis crée un arbre DOM. De la même manière, il crée le CSSOM avec le CSS. Le DOM et le CSSOM sont ensuite combinés, et nous obtenons finalement une structure à partir de laquelle nous pouvons commencer à peindre des pixels.

Le processus de peinture lui-même est intéressant. Dans Chrome, cet arbre combiné de DOM et de CSS est rasterisé par un logiciel appelé Skia. Si vous avez déjà utilisé l'élément canvas, l'API Skia vous semblera très familière. Il existe de nombreuses fonctions de style moveTo et lineTo, ainsi qu'un certain nombre de fonctions plus avancées. En gros, tous les éléments à peindre sont distillés dans un ensemble d'appels Skia qui peut être exécuté, et la sortie de est un tas de bitmaps. Ces bitmaps sont importés dans le GPU, qui les compose pour obtenir l'image finale à l'écran.

Domme à pixels

La chose à retenir est que la charge de travail de Skia est directement affectée par les styles que vous appliquez à vos éléments. Si vous utilisez des styles algorithmiques lourds, Skia aura plus de travail à effectuer. Colt McAnlis a écrit un article sur l'impact du CSS sur le poids de rendu de la page. Nous vous invitons à le lire pour en savoir plus.

Cela dit, la peinture prend du temps à être appliquée, et si nous ne la réduisons pas, nous dépasserons notre budget de frames d'environ 16 ms. Les utilisateurs remarqueront que nous avons manqué des images et verront cela comme un à-coup, ce qui nuit à l'expérience utilisateur de notre application. Nous ne voulons vraiment pas que cela se produise. Voyons donc quels types de choses nécessitent un travail de peinture et ce que nous pouvons faire à ce sujet.

Défilement

Chaque fois que vous faites défiler le navigateur vers le haut ou vers le bas, le contenu doit être repeint avant d'apparaître à l'écran. Tout est en ordre, cela ne représentera qu'une petite zone, mais même si c'est le cas, des styles complexes peuvent être appliqués aux éléments qui doivent être dessinés. Par conséquent, ce n'est pas parce que la surface à peindre est petite que la peinture sera appliquée rapidement.

Pour voir les zones qui sont repeintes, vous pouvez utiliser la fonctionnalité "Afficher les rectangles de peinture" dans les outils de développement de Chrome (il vous suffit de cliquer sur la petite roue dentée en bas à droite). Ensuite, lorsque les outils de développement sont ouverts, il vous suffit d'interagir avec votre page. Des rectangles clignotants indiquent où et quand Chrome a peint une partie de la page.

Afficher les rectangles à peindre dans les outils pour les développeurs Chrome
Afficher les rectangles de peinture dans les outils pour les développeurs Chrome

Les performances de défilement sont essentielles au succès de votre site. Les utilisateurs remarquent vraiment quand le défilement de votre site ou de votre application est lent et ils n'apprécient pas cela. Nous avons donc tout intérêt à conserver la peinture légère pendant le défilement afin que les utilisateurs ne voient pas de saccades.

J'ai déjà écrit un article sur les performances de défilement. Consultez-le si vous souhaitez en savoir plus sur les spécificités des performances de défilement.

Interactions

Les interactions sont une autre cause de travail de peinture : pointage, clics, pressions, glissements. Chaque fois que l'utilisateur effectue l'une de ces interactions, par exemple en passant la souris dessus, Chrome doit repeindre l'élément concerné. Et, comme pour le défilement, si une peinture volumineuse et complexe est requise, la fréquence d'images va baisser.

Tout le monde veut des animations d'interaction fluides et agréables. Nous devons donc à nouveau vérifier si les styles qui changent dans notre animation nous coûtent trop de temps.

Une combinaison malheureuse

Une démonstration avec des peintures coûteuses
Une démonstration avec des peintures chères

Que se passe-t-il si je fais défiler la page et que je déplace la souris en même temps ? Il est tout à fait possible que j'interagisse involontairement avec un élément lorsque je le fais défiler, ce qui déclenche une peinture coûteuse. Cela pourrait me faire dépasser mon budget de frames d'environ 16,7 ms (temps que nous devons respecter pour atteindre 60 images par seconde). J'ai créé une démonstration pour vous montrer exactement ce que je veux dire. En faisant défiler la page et en déplaçant la souris, vous devriez voir les effets de survol s'appliquer. Voyons ce que les outils pour les développeurs de Chrome en disent :

Les outils pour les développeurs de Chrome affichent des frames coûteuses
Outils pour les développeurs Chrome affichant des cadres coûteux

Dans l'image ci-dessus, vous pouvez voir que DevTools enregistre le travail de peinture lorsque je passe la souris sur l'un des blocs. J'ai choisi des styles très lourds dans ma démonstration pour illustrer mon propos. Je dépasse donc parfois mon budget de frames. La dernière chose que je veux, c'est avoir à effectuer ce travail de peinture inutilement, et surtout lors d'un défilement alors qu'il y a d'autres tâches à accomplir.

Alors, comment pouvons-nous empêcher cela de se produire ? En l'occurrence, la solution est assez simple à implémenter. L'astuce consiste à associer un gestionnaire scroll qui désactivera les effets de survol et définira un minuteur pour les réactiver. Cela signifie que nous garantissons que lorsque vous faites défiler la page, nous n'aurons pas besoin d'effectuer de peintures d'interaction coûteuses. Lorsque vous vous êtes arrêté pendant suffisamment longtemps, nous estimons que vous pouvez les réactiver sans risque.

Voici le code :

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

Comme vous pouvez le constater, nous utilisons une classe sur le corps pour déterminer si les effets de survol sont "autorisés" ou non. Les styles sous-jacents dépendent de la présence de cette classe :

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 
}

Et c'est tout ce que vous avez à faire !

Conclusion

Les performances de rendu sont essentielles pour que les utilisateurs apprécient votre application. Vous devez toujours essayer de limiter la charge de travail de peinture à 16 ms. Pour ce faire, vous devez intégrer les outils de développement tout au long du processus de développement afin d'identifier et de corriger les goulots d'étranglement lorsqu'ils surviennent.

Les interactions involontaires, en particulier sur les éléments qui utilisent beaucoup de peinture, peuvent être très coûteuses et nuire aux performances de rendu. Comme vous l'avez vu, nous pouvons utiliser un petit morceau de code pour résoudre ce problème.

Examinez vos sites et applications. Avez-vous besoin d'une couche de protection ?