Éviter les peintures inutiles

Introduction

Peindre les éléments d'un site ou d'une application peut s'avérer très onéreux, et cela peut avoir un effet négatif sur les performances d'exécution. Dans cet article, nous allons voir rapidement ce qui peut déclencher l'affichage dans le navigateur et comment éviter que des peintures ne s'affichent inutilement.

Peinture: présentation rapide

L'une des principales tâches d'un navigateur est de convertir le DOM et le CSS en pixels à l'écran, selon un processus assez complexe. Il commence par lire le balisage, puis crée une arborescence DOM. Il effectue la même opération avec le CSS et, à partir de là, crée le CSSOM. Le DOM et CSSOM sont ensuite combinés et, finalement, nous obtenons une structure à partir de laquelle nous pouvons commencer à peindre quelques pixels.

Le processus de peinture lui-même est intéressant. Dans Chrome, l'arborescence combinée du DOM et du CSS est rastérisée par un logiciel appelé Skia. Si vous avez déjà joué avec l'élément canvas, l'API de Skia vous semble familière. Il existe de nombreuses fonctions de style moveTo et lineTo, ainsi que plusieurs fonctions plus avancées. En fait, tous les éléments à peindre sont distillés dans une collection d'appels Skia pouvant être exécutés, et la sortie est constituée d'un ensemble de bitmaps. Ces bitmaps sont importés sur le GPU, qui aide celui-ci en les compilant pour afficher l'image finale à l'écran.

Dom en pixels

Ce qu'il faut retenir, c'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 utilisant beaucoup d'algorithmes, Skia va avoir encore du travail. Colt McAnlis a rédigé un article sur l'impact du CSS sur la pondération d'affichage des pages. Nous vous recommandons de le lire pour en savoir plus.

Cela dit, l'exécution du travail de peinture prend du temps. Si nous ne le raccourcissons pas, nous dépasserons notre budget de frames d'environ 16 ms. Les utilisateurs remarqueront que nous avons manqué des images et les considéreront comme des à-coups, ce qui nuit à l'expérience utilisateur de notre application. Ce n'est vraiment pas ce que nous voulons, alors voyons quels types d'éléments sont nécessaires pour appliquer l'application de peinture, et ce que nous pouvons faire pour y remédier.

Utilisez le défilement

Chaque fois que vous faites défiler le contenu vers le haut ou vers le bas, le contenu doit être repeint avant qu'il ne s'affiche à l'écran. Tout ceci ne représente qu'une petite zone, mais même dans ce cas, des styles complexes peuvent être appliqués aux éléments qui doivent être dessinés. Ce n'est pas parce que vous avez une petite zone à peindre que ça va se faire vite.

Pour voir quelles zones sont repeintes, vous pouvez utiliser la fonctionnalité "Show Paint Rectangles" (Afficher les rectangles à peinture) des outils de développement Chrome (appuyez simplement sur le petit engrenage en bas à droite). Ensuite, une fois que les outils de développement sont ouverts, il vous suffit d'interagir avec votre page. Des rectangles clignotants vous indiquent où et quand Chrome a peint une partie de la page.

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

Les performances de défilement sont essentielles à la réussite de votre site. Les utilisateurs remarquent vraiment les problèmes de défilement sur votre site ou application et ils ne les apprécient pas. Nous avons donc un intérêt direct à maintenir la luminosité de l'œuvre de peinture lors des défilements afin que les utilisateurs ne voient pas d'à-coups.

J'ai déjà rédigé un article sur les performances de défilement. Consultez-le pour en savoir plus sur les spécificités de ces performances.

Interactions

Les interactions sont une autre cause de peinture: les survols, les clics, les pressions, les déplacements. Chaque fois que l'utilisateur effectue l'une de ces interactions (par exemple, lorsqu'il pointe dessus), Chrome doit repeindre l'élément concerné. De même que pour le défilement, si un rendu complexe et volumineux est requis, la fréquence d'images diminuera.

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

Une combinaison malheureuse

Démonstration avec des peintures onéreuses
Une démonstration avec des peintures onéreuses

Que se passe-t-il si je fais défiler la page et que je déplace la souris en même temps ? Il m'est parfaitement possible d'"interagir" par inadvertance avec un élément lorsque je le fais défiler, ce qui déclenche un effet de peinture coûteux. Cela pourrait, à son tour, dépasser mon budget de frames d'environ 16,7 ms (le temps nécessaire pour rester en dessous de cette limite pour atteindre 60 images par seconde). J'ai créé une démonstration pour vous montrer exactement ce que je veux dire. Si vous faites défiler l'écran et que vous déplacez la souris, vous devriez voir les effets de survol s'afficher. Voyons ce que les outils pour les développeurs Chrome en font:

Outils pour les développeurs Chrome affichant des cadres coûteux
Outils pour les développeurs Chrome affichant des cadres coûteux

Dans l'image ci-dessus, vous pouvez voir que les outils de développement enregistrent la tâche lorsque je passe la souris sur l'un des blocs. J'ai utilisé des styles très lourds dans ma démonstration pour faire clairement la différence. J'épuise mon budget de frame de temps en temps. La dernière chose que je veux, c'est de devoir faire ce travail inutilement, surtout pendant un défilement quand il y a autre travail à faire !

Alors, comment pouvons-nous empêcher que cela ne se produise ? Le correctif est assez simple à mettre en œuvre. 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 vous garantissons que lorsque vous faites défiler l'écran, nous n'aurons pas besoin d'effectuer des peintures d'interaction coûteuses. Lorsque vous vous arrêtez suffisamment longtemps pour faire une pause, vous pouvez le réactiver.

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 voir, nous utilisons une classe dans le corps pour déterminer si les effets de survol sont "autorisés" ou non. Les styles sous-jacents dépendent 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 d'affichage sont essentielles pour que les utilisateurs bénéficient de votre application. Veillez donc toujours à ce que votre charge de travail de peinture ne dépasse pas 16 ms. Pour ce faire, nous vous conseillons d'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.

Les interactions involontaires, en particulier sur les éléments gourmands en peinture, peuvent s'avérer très coûteuses et réduire les performances d'affichage. Comme vous l'avez vu, un petit extrait de code permet de résoudre ce problème.

Pensez à vos sites et applications. Un peu de protection pourrait-il leur être utile ?