Faire bouger sa page web, c'est mettre des paillettes dans les yeux de ses utilisateurs.

La semaine dernière, on a regardé comment fonctionne un navigateur afin de mieux comprendre comment choisir les propriétés CSS que l'on doit animer. On a travaillé sur le Layout. En fin d'article, j'avais précisé que ce n'était pas le seul point sur lequel on peut avoir une influence. On peut aussi chercher à optimiser la phase de Painting. C'est donc cette partie que l'on va explorer cette semaine.

Pour rappel, cette série dédiée aux animations performantes est découpée en trois parties :

  1. Animer les bonnes propriétés CSS
  2. Préparer le navigateur aux animations (Vous êtes ici.)
  3. Faire les choses dans le bon ordre en JS

Ces trois parties sont assez théoriques et expliquent ce qu'il faut éviter et pourquoi. Il faudra attendre la deuxième série sur les animations pour parler d'implémentations concrètes.

TL;DR

Si un objet est destiné à bouger, il faut prévenir le navigateur en utilisant la règle CSS :

  • will-change: <propriete-animee>

Mais pourquoi utiliser will-change ? Qu'est ce que ça change au niveau du rendu navigateur ? Et comment choisir quand est-ce qu'il faut le mettre ?

Les layers

Pour comprendre pourquoi on utilise will-change, il faut comprendre la notion de layer (ou calque).

Comment d'après vous sont dessinées les choses à l'écran ? Généralement, la première solution qui vient à l'esprit est de dessiner les pixels un par un.

Ainsi, pour dessiner un bouton, on commence par dessiner le fond de celui-ci. On dit donc à l'ordinateur de colorier, un par un, les pixels qui composent le fond. Puis, on ajoute le texte en précisant à l'ordinateur quels pixels doivent changer de couleur.

C'est ce que fait le navigateur au moment du Painting. Il définit la couleur que doit avoir chaque pixel pour pouvoir les afficher à l'écran.

Si on reste sur cette approche, à chaque fois que quelque chose change, il faut redessiner l'ensemble de l'écran. Pourtant, si le bouton doit uniquement se décaler de quelques pixels sur la droite, c'est dommage de devoir recalculer l'ensemble des pixels du bouton.

C'est ici qu'intervient les layers. L'idée est de dire que l'on connaît déjà la position des pixels, et qu'il suffit de les déplacer par blocs. C'est exactement la même chose que ce que vous feriez avec du papier calque. En dessinant sur plusieurs feuilles et en les superposant, vous n'avez pas besoin de tout redessiner à chaque fois que vous voulez changer un élément (ex : les celluloïds).

Ce qu'il y a de top dans tout ça, c'est que dans l'ensemble le navigateur s'en charge automatiquement pour vous. Mais quand il n'arrive pas à déterminer les bons calques, comment l'aider ?

Identifier ce qui est redessiné dans la page

Tout d'abord, avant de savoir comment l'aider, il faut savoir où l'aider. Pour cela, il va falloir identifier quelles sont les parties de votre page qui sont repeintes inutilement.

On demande donc au navigateur d'afficher ce qu'il repeint. C'est une option assez cachée sur les différents navigateurs. Cependant, elle permet de voir visuellement quelles sont les parties de la page qui posent problème.

Sur Chrome, il faut ouvrir les dev tools, et tout en bas, il y a un onglet Console. Il faut cliquer sur le bouton à gauche de celle-ci et activer l'onglet Rendering. Dans celui-ci il faut alors cocher l'option Paint Flashing.

Sur Firefox, dans les dev tools, en haut à droite, il faut ouvrir les Toolbox Options. Et dans la section Available Toolbox Buttons, il faut activer Highlight painted area. Le bouton apparaît alors dans la liste des boutons en haut à droite des dev tools et il ne reste plus qu'à l'activer.

Une fois l'option activée, vous pouvez scroller sur la page surlaquelle vous êtes et vous verrez des zones vertes apparaître (notamment la scrollbar).

Si lors de vos animations, quelque chose est repeint constamment, c'est mauvais signe.

Voici un exemple qui lag (j'y ai mis tout mon talent) :

J'ai utilisé ces box-shadows hiddeuses pour avoir quelque chose qui lag sur desktop. Cependant, dans la vraie vie, ce cas se présente plutôt lorsque vous avez beaucoup de contenu dans l'élément animé.

Eviter les repaints

Maintenant qu'on sait identifier ce qui pose problème, vous vous en doutez, le but va être de forcer la création de nouveaux layers.

Il y a une propriété faite exprès pour ça : will-change. Celle-ci prévient le navigateur qu'une propriété va changer durant l'animation à venir. Le navigateur va alors créer un layer séparé pour optimiser l'affichage.

.class {
  will-change: transform;
}

En détails

Il faut tout de même retenir quelques point sur cette propriété, parce que tout de même, tout n'est pas toujours magique !

  • Si vous en utilisez trop, cela consomme beaucoup de mémoire et cela aura l'effet inverse : le navigateur sera encore moins performant.

  • Ce n'est compatible qu'avec les propriétés qui ne changent pas l'affichage des éléments. Par exemple, si vous changez la couleur, le navigateur sera tout de même obligé de repeindre des pixels. Essayez donc de rester sur transform et opacity.

  • La propriété will-change est inutile si vous utilisez les keyframes en CSS en tandem avec les propriétés transform et/ou opacity. Cela vient du fait qu'en utilisant les keyframes, le navigateur sait déjà que l'élément va bouger.

  • (moins utile à savoir) Si vous utilisez position: fixed, un layer ne sera pas nécessairement créé automatiquement. Cela dépend de la denisté de votre écran. (source)

Conclusion

En bref, cette propriété est tout de même assez magique. Mais elle corrobore surtout le fait qu'il faut essayer de rester sur les animations basées sur transform et opacity si on veut éviter d'avoir des problèmes.

En tout cas, avant de l'utilisez, pensez à vérifier qu'elle est vraiment utile en passant par vos dev tools.

La semaine prochaine, on passera côté JS ! En effet, parfois, on ne peut pas se contenter du CSS pour animer ses pages. Mais de nouveaux challenges se présentent si on change de langage. On parlera encore un petit peu de Layout, mais aussi d'orchestration d'évènement.


En attendant, voici quelques sources pour vous permettre d'approfondir le sujet :