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

Le hic, c'est que ce n'est pas facile à faire. Souvent, on se retrouve avec des maquettes qui mettent l'eau à la bouche et on les massacre à l'intégration. En général, parti de ce constat, il ne reste plus que deux possibilités : soit on décide que c'est la faute du graphiste, soit on cherche et propose des solutions.

Cela dit, c'est un sujet très vaste, qui mériterait bien plus que quelques articles. Je vais donc l'aborder par petits bouts. Cette première série dédiée au sujet parlera des performances.

Celle-ci sera découpée en trois parties :

  1. Animer les bonnes propriétés CSS (Vous êtes ici.)
  2. Préparer le navigateur aux animations
  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

Essayez de n'utiliser que les propriétés CSS qui ne changent pas la taille réelle des éléments. Celles qui vous éviteront un maximum de problèmes sont :

  • transform
  • opacity

Le but de cet article va être de comprendre pourquoi en examinant le fonctionnement des navigateurs.

Comment faire des animations en CSS ?

Il existe deux types d'animations en CSS :

  • transition : une propriété CSS a changé, et le navigateur fait en sorte que le passage de l'ancienne propriété à la nouvelle soit fluide
  • animation : une propriété CSS change plusieurs fois au cours d'un même mouvement (via des keyframes), et le navigateur fait en sorte de rendre le tout fluide. Ces animations peuvent être répétées plusieurs fois si nécessaire.

Tout le contenu de cette série sera valable quelque soit le type d'animation choisi.

Je ne développerai pas sur l'usage de ces propriétés dans cet article. Cependant, pour que ce soit plus concret pour ceux d'entre vous qui n'ont jamais vu d'animations CSS, voici à quoi ressemble une transition :

Pour faire cette transition lors du hover, j'ai utilisé le CSS suivant :

button {
  transition: transform 0.3s ease;
}
button:hover, button:focus {
  transform: scale(1.2);
}

Dans la propriété transition, je définis la propriété qui est animable (transform), la durée de transition (0.3s) et le timing de votre transition (ease). Vous pouvez aussi retarder une transition en ajoutant une nouvelle durée après le timing.

Mais mes animations sont lentes !

Hé, oui ! Même si le navigateur fait beaucoup de choses intelligentes à votre place, il ne peut pas tout faire parfaitement. Et quand on sait qu'on n'a que 16.67 millième de secondes pour faire une étape de l'animation et atteindre les 60fps... on se dit qu'il y a du boulot !

Pour rendre vos animations rapides, il va falloir se mettre à la place du navigateur pour comprendre ce qui ne va pas.

Comment fonctionne un navigateur web ?

Pour afficher une page, un navigateur web doit passer par plusieurs étapes.

  1. Tout d'abord, quand votre page arrive, elle est en HTML. Le navigateur doit la parser pour la transformer en des objets avec lesquels il peut travailler. Ainsi, pour chaque balise HTML est créé un élément du DOM (Document Object Model). (Ce sont ces éléments du DOM qui sont mis à disposition en JavaScript.)

  2. Place au CSS. Le navigateur va parser les feuilles de style et les transformer en Style Rules. Le but est de faire en sorte que, lors de la prochaine étape, il soit rapide de déterminer quelles propriétés CSS s'appliquent à chaque élément du DOM.

  3. Maintenant que le navigateur connaît le contenu et qu'il sait quelles règles de style appliquer, le navigateur combine les deux et construit un nouvel arbre qu'on appelle le Render Tree ou Render Application. A partir de celui-ci, toutes les informations sont disponibles pour faire le rendu de l'application. Cependant, pour l'instant, si on devait représenter cet arbre sur une page, tous les éléments seraient en haut à gauche.

  4. Pour les placer au bon endroit, on passe à l'étape du Layout (ou Reflow). Cette étape consiste à déterminer comment agencer les éléments les uns par rapport aux autres. C'est cette étape à laquelle je vais m'intéresser dans cet article.

  5. Et enfin, le navigateur passe à l'étape du Painting qui sert à afficher votre page sur votre navigateur.

Pour résumer le tout en un seul diagramme, cela devrait ressembler à ça :

Schéma représentant les 5 étapes sus-citées
Fonctionnement de Webkit (source)

Pourquoi s'intéresser plus particulièrement au Layout ?

Parce que c'est une étape très couteuse qui peut être optimisée voire même évitée. Il nous restera donc beaucoup plus de temps pour faire le reste.

Pourquoi couteuse ?

En théorie

Si vous vous souvenez de ce que j'ai dit, le Layout est l'étape qui permet de dire comment et où va être placé chacun de vos éléments sur la page.

Pour faire cette opération, le navigateur va prendre les balises de la page une par une et va les positionner. Pour ce faire, sur chaque balise, il a besoin de savoir :

  • quelle place est disponible dans l'élément parent
  • combien de place est nécessaire pour s'afficher

En pratique

Sur un exemple concret, qu'est ce que ça donne ?

<body>
  <nav>
    <h1>Titre</h1>
    <ul>
      <li>Menu 1</li>
      <li>Menu 2</li>
      <li>Menu 3</li>
    </ul>
  </nav>
  <main>
    <h2>Ma page</h2>
    <p>Lorem ipsum dolor sit amet</p>
  </main>
</body>

Ici, l'étape de Layout va commencer par représenter la balise nav.

Il calcule donc la position du titre et celui-ci se positionne à gauche et prend le moins de place possible (float: left).

Une fois que le titre a été positionné, place au menu. Il essaye alors de caler le maximum d'éléments du menu sur une même ligne (display: inline-block), à droite du titre. S'il n'y arrive pas, il fait plusieurs lignes. Et si ce n'est toujours pas possible, la liste passe sous le titre.

Le positionnement de la navigation est fini et le navigateur peut passer à la suite en positionnant de la même façon le main qui sera en dessous du nav.

Dans le cadre d'une animation

Maintenant, imaginons que vous changiez la taille de votre titre au survol.

h1:hover { font-size: 2em; }

Cela veut dire que la taille que va prendre le titre va doubler. Mais cela veut aussi dire qu'il reste moins de place pour la liste du menu, et donc qu'elle va potentiellement passer sur plusieurs lignes et prendre plus de place en hauteur. Et si la navigation prend plus de place, le reste de la page va aussi descendre et donc a besoin d'être recalculé. Bref, il a besoin de tout recalculer à partir de la seule balise qui a changé de style.

En soit, qu'il recalcule tout n'est pas très grave parce que à l'échelle de l'utilisateur ce n'est pas très long. Par contre, si ce changement est animé, cela veut dire que chaque nouvel affichage prendra plus longtemps, et donc que l'animation sera ralentie, voire moche.

Comment l'optimiser ?

Pour éviter d'avoir à tout recalculer à chaque fois, on va essayer de ne plus changer le Layout à chaque étape de l'animation. C'est possible parce que certaines propriétés ne changent pas le flow de la page.

C'est valable notamment pour toutes les propriétés qui affectent les couleurs (dont opacity), mais aussi pour la propriété transform étant donné que celle-ci n'a pas d'impact sur le reste des éléments.

Comment savoir si la propriété est bonne ou mauvaise ?

Pour le constater par vous même, vous pouvez ouvrir vos DevTools dans votre navigateur préféré et aller dans l'onglet permettant d'inspecter les performances de votre application (Timeline sur Chrome&Co, Performance sur Firefox). Une fois sur l'onglet, il vous faut enregistrer une séquence pendant laquelle vous lancerez manuellement votre animation.

Timeline Google Chrome avec du Layout
Voici à quoi ressemble la Timeline enregistrée via Chrome

Et ce qui va vous intéresser, c'est la partie où il y a écrit Layout (en violet). Si elle est présente tout au long de votre animation, c'est que votre animation est couteuse. Et, bien que cela puisse s'afficher correctement dans votre navigateur, pensez aux mobiles qui auront du mal à suivre le rythme !

Il est important de faire le test sur plusieurs navigateurs car l'animation peut être rapide sur l'un et lente sur l'autre.

Vous pouvez aussi regarder sur CSS Triggers. Mais méfiez vous de ce qu'il vous dit car je suis tombé sur quelques incohérences par rapport à ce que j'ai constaté dans les DevTools.

Conclusion

Voilà, vous savez maintenant comment bien choisir vos propriétés CSS et surtout comment éviter celles qui vous pourriront vos animations.

Le seul problème, c'est que ce n'est pas évident de penser de cette façon quand on débute. Mais avec un peu d'imagination, c'est tout à fait possible de n'animer qu'en utilisant ces propriétés. Si vous êtes impatients vous pouvez déjà vous intéresser à la technique FLIP présentée par @aerotwist. Sinon, vous pouvez attendre ma nouvelle série d'articles sur le sujet dans 3-4 semaines. :)

La semaine prochaine, toujours sur les performances, nous verrons qu'il est possible d'optimiser aussi les phases de Painting. Alors à très vite :)


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