10 principes pour des animations web fluides
Le guide complet pour obtenir des animations à 60 fps avec CSS

Depuis le lancement de Gyroscope l’an dernier, beaucoup de gens nous demandent quelle bibliothèque JavaScript nous utilisons pour nos animations. Nous avons pensé la publier, mais ce n’est pas vraiment là que la magie opère.
Nous ne voulons pas que les gens se croient dépendants d’un plugin JavaScript spécial qui résoudrait magiquement ces problèmes. Pour l’essentiel, nous profitons simplement des progrès récents des navigateurs, des GPU et de la spécification CSS3.
Il n’y a pas de solution miracle pour de belles animations, à part passer beaucoup de temps à les tester et à les optimiser. Cela dit, après des années d’expérimentation et de tests aux limites des navigateurs, nous avons dégagé une série de principes de design & de code qui donnent de façon fiable de belles animations. Ces techniques devraient vous donner des pages fluides, qui fonctionnent dans les navigateurs modernes sur ordinateur comme sur mobile et, surtout, faciles à maintenir.

La technologie et l’implémentation varieront un peu selon chacun, mais les principes généraux devraient être utiles dans presque toutes les situations.
Qu’est-ce qu’une animation ?
Les animations existaient bien avant internet, et on pourrait passer une vie à apprendre à les réussir. Mais les faire pour le web impose des contraintes et des défis particuliers.
Pour une fluidité à 60 fps, chaque image doit être rendue en moins de 16 ms ! Ce n’est pas beaucoup, il faut donc trouver des façons très efficaces de rendre chaque image.
Il existe des dizaines de façons d’animer sur le web. Par exemple, la pellicule est une approche antérieure à internet : des images dessinées à la main, légèrement différentes, sont échangées plusieurs fois par seconde pour créer l’illusion du mouvement.
Twitter a récemment utilisé cette approche simple pour sa nouvelle animation de cœur, en faisant défiler un sprite d’images.

Cet effet aurait pu être obtenu avec une foule de petits éléments animés séparément, ou peut-être en SVG, mais ç’aurait été inutilement complexe et sans doute moins fluide.

Dans bien des cas, vous voudrez utiliser la propriété CSS transition pour animer automatiquement un élément quand il change. Cette technique est aussi appelée « tweening », c’est-à-dire une transition entre deux valeurs différentes. Elle a l’avantage de s’annuler ou de s’inverser facilement, sans avoir à écrire toute cette logique. C’est idéal pour les animations qu’on lance et qu’on oublie, comme les séquences d’introduction, ou pour des interactions simples comme le survol.
Pour aller plus loin : All you need to know about CSS Transitions

Dans d’autres cas, la propriété CSS animation, basée sur des keyframes, sera idéale pour des détails d’arrière-plan qui tournent en continu. Par exemple, les anneaux du logo Gyroscope sont programmés pour tourner sans arrêt. Les rapports d’engrenage sont un autre bon cas d’usage de la syntaxe CSS animation.
Sans plus attendre, voici quelques conseils qui devraient nettement améliorer les performances de vos animations…
#1
Ne modifiez aucune propriété à part opacity ou transform !
Même si vous pensez que ça peut passer, non !
Ce seul principe de base vous emmène déjà à 80 % du chemin, même sur mobile. Vous l’avez probablement déjà entendu, l’idée n’est pas neuve, mais elle est rarement suivie. C’est l’équivalent web du « mangez sainement et faites du sport » : ça sonne comme un bon conseil, et vous l’ignorez sans doute.
C’est assez simple une fois qu’on prend l’habitude de raisonner ainsi, mais cela peut représenter un grand saut pour qui a l’habitude d’animer les propriétés CSS classiques.
Par exemple, pour rendre quelque chose plus petit, vous pouvez utiliser transform: scale() au lieu de changer la largeur. Pour le déplacer, au lieu de toucher aux marges ou au padding, ce qui obligerait à recalculer toute la mise en page à chaque image, il suffit d’un simple transform: translateX ou transform: translateY.
Pourquoi ça marche ?
Pour un humain, changer la largeur, la marge ou d’autres propriétés ne semble pas grand-chose, et paraît même préférable puisque c’est plus simple, mais du point de vue du travail que doit faire la machine, ces opérations n’ont rien à voir et l’une est bien, bien pire.
Les équipes des navigateurs ont fourni un excellent travail d’optimisation de ces opérations. Les transforms sont très faciles à exécuter efficacement et peuvent souvent s’appuyer sur votre carte graphique sans avoir à refaire le rendu des éléments.
Vous pouvez vous lâcher au premier chargement de la page : arrondissez tous les coins, utilisez des images, mettez des ombres partout, et si vous vous sentez particulièrement téméraire, ajoutez même un flou dynamique. Si ça n’arrive qu’une fois, quelques millisecondes de calcul en plus n’ont pas d’importance. Mais une fois le contenu rendu, vous ne voulez plus tout recalculer en boucle.
Pour aller plus loin : Moving elements with translate (Paul Irish)
#2
Cachez le contenu à la vue de tous.
Utilisez pointer-events: none avec une opacité nulle pour masquer des éléments
Celui-ci comporte quelques réserves selon les navigateurs, mais si vous ne visez que webkit et les autres navigateurs modernes, il vous simplifiera beaucoup la vie.
Il y a longtemps, quand les animations passaient par animate() de jQuery, une grande partie de la complexité des fondus venait du basculement entre display: none et block au bon moment. Trop tôt, l’animation ne se terminait pas ; trop tard, du contenu invisible à opacité nulle recouvrait votre page. Il fallait des callbacks partout pour faire le ménage une fois l’animation finie.
La propriété CSS pointer-events (qui existe depuis longtemps déjà, mais qu’on utilise peu) fait qu’un élément ne répond plus aux clics ni aux interactions, comme s’il n’était pas là. Elle s’active et se désactive facilement en CSS, sans interrompre les animations ni affecter le rendu ou la visibilité.
Combinée à une opacité de zéro, elle a en gros le même effet que display: none, mais sans le coût de performance des nouveaux rendus. Pour masquer des choses, je mets généralement l’opacité à 0 et je coupe pointer-events, puis j’oublie l’élément en sachant qu’il se tiendra tranquille.
Ça marche particulièrement bien avec des éléments en position absolue, parce qu’on est certain qu’ils n’ont absolument aucun effet sur le reste de la page.
Cela laisse aussi un peu plus de marge, puisque le timing n’a pas besoin d’être parfait : ce n’est pas dramatique qu’un élément reste cliquable ou recouvre d’autres choses une seconde de plus qu’il n’était visible, ou qu’il ne devienne cliquable qu’une fois complètement apparu.
#3
N’animez pas tout en même temps.
Faites plutôt de la chorégraphie.
Une animation seule peut être fluide, mais lancée en même temps que beaucoup d’autres, elle se dégradera sans doute. Il est très facile de faire une démo basique où tout tourne bien, et un ordre de grandeur plus difficile de tenir cette performance sur un site complet. Il est donc important de bien les ordonnancer.
Vous voudrez étaler les timings pour que tout ne démarre pas et ne tourne pas exactement au même instant. En général, 2 ou 3 choses peuvent bouger en même temps sans ralentissement, surtout si elles ont été déclenchées à des moments légèrement différents. Au-delà, vous risquez des à-coups.
À moins qu’il n’y ait littéralement qu’une seule chose sur vos pages, il faut comprendre la notion de chorégraphie. Le mot évoque la danse, mais il compte tout autant pour animer des interfaces. Les éléments doivent arriver de la bonne direction et au bon moment. Même s’ils sont indépendants, ils doivent donner l’impression d’un ensemble bien conçu.
Le material design de Google fait des propositions intéressantes sur le sujet. Ce n’est pas la seule bonne façon de faire, mais c’est une piste à envisager et à tester.

Pour aller plus loin : Google Material Design · Motion
#4
Des délais de transition légèrement croissants facilitent la chorégraphie du mouvement.
Chorégraphier des animations est vraiment important et demandera beaucoup d’essais et de tests avant de sonner juste. Le code, en revanche, n’a pas besoin d’être compliqué.
Je change en général une seule classe sur un élément parent (souvent sur body) pour déclencher un ensemble de transitions, chacune avec son propre transition-delay pour arriver au bon moment. Côté code, vous n’avez qu’un seul changement d’état à gérer, sans maintenir des dizaines de timings dans votre JavaScript.

Décaler une série d’éléments est une façon simple et efficace de les chorégraphier. C’est puissant parce que c’est à la fois joli et générateur de performance précieuse : rappelez-vous que vous ne voulez que quelques choses en mouvement à la fois. Il faut les étaler assez pour que chacune soit fluide, mais pas au point que l’ensemble paraisse lent. Il doit y avoir assez de recouvrement pour donner l’impression d’un flux continu plutôt que d’une suite d’éléments isolés.
Exemple de code
Il y a deux techniques simples pour décaler vos éléments, surtout s’il s’agit d’une longue liste. S’il y a moins de 10 éléments, ou un nombre très prévisible (comme dans une page statique), je précise en général les valeurs en CSS. C’est le plus simple et le plus facile à maintenir.

Pour des listes plus longues ou du contenu très dynamique, les timings peuvent être calculés dynamiquement en bouclant sur chaque élément.

Il y a en général deux variables : votre délai de base, puis l’écart entre chaque élément. L’équilibre est délicat à trouver, mais quand vous tombez sur les bons chiffres, le résultat est parfait.
#5
Utilisez un multiplicateur global pour concevoir au ralenti
Puis accélérez tout ensuite.
Dans la conception d’animations, tout est affaire de timing. 20 % du travail consiste à implémenter quelque chose, les 80 % restants à trouver les bons paramètres & les bonnes durées pour que tout soit synchronisé et fluide.
C’est surtout vrai quand on travaille la chorégraphie de plusieurs éléments et qu’on cherche à tirer de la performance et du parallélisme de la page : voir l’ensemble au ralenti facilite énormément les choses.
Que vous utilisiez Javascript ou un préprocesseur CSS comme SASS (que nous adorons), il devrait être assez simple de faire un peu de calcul en plus et de construire à partir de variables.
Assurez-vous qu’il soit pratique d’essayer différentes vitesses ou différents timings. Par exemple, si une animation saccade même à 1/10 de la vitesse, il y a peut-être un problème de fond. Si elle est fluide une fois étirée 50 fois, il ne reste qu’à trouver la vitesse maximale à laquelle elle tient. Il est difficile de repérer des soucis de 5 millisecondes à pleine vitesse, mais si vous ralentissez tout, ils sautent aux yeux.
Pour les animations très complexes, ou pour résoudre des goulots d’étranglement retors, pouvoir observer au ralenti est vraiment utile.
L’idée principale, c’est de soigner une foule de détails pendant que ça se déroule lentement, puis d’accélérer l’ensemble pour que ce soit parfait. Ce sera très subtil, mais l’utilisateur remarquera la fluidité et les détails.
Cette fonction existe d’ailleurs dans OS X : si vous faites maj-clic sur le bouton de réduction ou sur l’icône d’une app, vous verrez l’animation au ralenti. À une époque, nous avions même implémenté ce ralenti dans Gyroscope, déclenché par la touche maj.
#6
Filmez votre interface et rejouez les vidéos pour prendre un précieux recul.
Un autre point de vue aide parfois à y voir plus clair, et la vidéo s’y prête très bien.
Certains construisent une vidéo dans After Effects, puis tentent de la reproduire sur un site. Je fais souvent l’inverse : j’essaie de tirer une bonne vidéo de l’interface d’un site.
Pouvoir publier un Vine* ou une vidéo de quelque chose place la barre assez haut. Un jour, enthousiasmé par ce que je venais de construire, j’ai voulu en faire un enregistrement pour le montrer à des amis.
Mais en le revoyant, j’ai remarqué plein de choses qui n’allaient pas. Il y avait un gros à-coup et tous les timings étaient légèrement faux. Ça m’a fait grincer des dents, et au lieu de l’envoyer, j’ai compris qu’il restait beaucoup de travail.
On passe facilement à côté quand on utilise l’interface en temps réel, mais regarder les animations en vidéo, encore et encore ou au ralenti, rend le moindre défaut criant.
On dit que la caméra fait paraître 10 livres de plus. Peut-être qu’elle ajoute aussi 10 images.
C’est devenu une partie importante de ma méthode de travail : regarder des vidéos au ralenti de mes pages et corriger dès qu’une image ne semble pas juste. C’est facile de tout mettre sur le dos des navigateurs lents, mais avec un peu plus d’optimisation et de tests, on peut venir à bout de ces problèmes.
Quand vous n’avez plus honte des à-coups repérés en vidéo et que la vidéo vous paraît assez bonne pour être partagée, la page est probablement prête à sortir.
#7
L’activité réseau peut provoquer des ralentissements.
Préchargez ou différez les grosses requêtes HTTP
Les images sont souvent en cause, qu’il s’agisse de quelques grosses (un grand arrière-plan, par exemple), d’une multitude de petites (imaginez 50 avatars qui se chargent) ou simplement de beaucoup de contenu (une longue page avec des images jusqu’au pied de page).
Au premier chargement, une foule de choses s’initialisent et se téléchargent. Les analytics, les pubs et les autres scripts tiers aggravent encore la situation. Parfois, retarder toutes les animations de quelques centaines de millisecondes après le chargement fait des merveilles.
N’optimisez pas ce point à l’excès tant que ce n’est pas nécessaire, mais une page compliquée peut demander des délais et des timings de contenu très précis pour tourner correctement. En général, chargez le moins de données possible au départ, puis poursuivez le chargement du reste de la page une fois le gros du travail et les animations d’intro terminés.
Sur les pages riches en données, le travail de chargement peut être considérable. Une animation qui marche bien avec du contenu statique peut s’effondrer dès qu’on charge de vraies données en même temps. Si quelque chose devrait marcher, ou marche parfois et parfois pas, je vous conseille de regarder l’activité réseau pour vérifier que rien d’autre ne tourne au même moment.
#8
Ne vous accrochez pas directement au scroll.
Ça a l’air d’une bonne idée, mais ça n’en est pas vraiment une.
Les animations liées au défilement ont gagné beaucoup de popularité ces dernières années, en particulier celles à base de parallaxe ou d’autres effets spéciaux. Qu’elles relèvent ou non du bon design se discute, mais il y a de meilleures et de moins bonnes façons de les implémenter techniquement.
Une manière raisonnablement performante de faire dans cette catégorie est de traiter le franchissement d’une certaine distance de défilement comme un événement, et de ne déclencher les choses qu’une fois. Sauf si vous savez vraiment ce que vous faites, je conseille d’éviter cette catégorie, tant il est facile de se tromper et difficile de maintenir le résultat.
Pire encore : réécrire votre propre barre de défilement au lieu d’utiliser celle du navigateur, autrement dit le scrolljacking. Ne faites pas ça, s’il vous plaît.
C’est l’une de ces règles particulièrement utiles sur mobile, mais qui reste sans doute une bonne pratique pour l’expérience utilisateur idéale.
Si vous tenez à un type d’expérience précis centré sur le défilement ou sur des événements particuliers, je conseille d’en faire un prototype rapide pour vérifier qu’il tient la route avant de passer beaucoup de temps à le concevoir.
#9
Testez sur mobile tôt & souvent.
La plupart des sites sont construits sur un ordinateur, et le plus souvent testés sur la machine qui les a construits. L’expérience mobile & les performances d’animation passent donc souvent au second plan. Certaines technologies (comme canvas) ou certaines techniques d’animation peuvent moins bien tourner sur mobile.
Pourtant, avec un code & une optimisation corrects (voir la règle n° 1), l’expérience mobile peut être encore plus fluide que sur ordinateur. L’optimisation mobile était autrefois un sujet épineux, mais les nouveaux iPhone sont désormais plus rapides que la plupart des portables ! Si vous avez suivi les conseils précédents, vous obtiendrez peut-être d’excellentes performances mobiles dès le départ.

L’usage mobile représentera une part importante de presque tous les sites. Ça peut sembler extrême, mais je conseille de consulter le vôtre exclusivement depuis votre téléphone pendant une semaine entière. Être forcé d’utiliser la version mobile ne devrait pas ressembler à une punition, et pourtant ce sera souvent le cas.
Continuez d’améliorer le design & les performances jusqu’à ce que ce soit aussi soigné et pratique que la grande version du site.
Si vous vous obligez à n’utiliser que votre site mobile pendant une semaine, vous finirez probablement par l’optimiser au point d’en faire une meilleure expérience que la grande. Être agacé en l’utilisant chaque jour en vaut la peine, si cela permet de corriger les problèmes avant que vos utilisateurs ne les rencontrent !
#10
Testez souvent sur plusieurs appareils
La taille d’écran, la densité ou l’appareil peuvent tout changer
Beaucoup de facteurs, au-delà du mobile contre l’ordinateur, peuvent affecter fortement les performances : le fait qu’un écran soit « retina » ou non, le nombre total de pixels de la fenêtre, l’âge du matériel, etc.
Même si Chrome et Safari sont tous deux basés sur Webkit avec une syntaxe proche, chacun a ses particularités. Chaque mise à jour de Chrome peut corriger des choses et en casser d’autres, il faut donc rester en alerte.
Bien sûr, vous ne voulez pas construire seulement pour le plus petit dénominateur commun, alors trouver des façons astucieuses d’ajouter ou de retirer progressivement les fioritures peut être très utile.
Je passe régulièrement de mon petit MacBook Air à mon grand iMac, et chaque aller-retour révèle de petits problèmes et des améliorations à faire, surtout sur les performances d’animation, mais aussi sur le design général, la densité d’information, la lisibilité, etc.
Les media queries sont des outils très puissants pour traiter ces différents cas : styler différemment selon la hauteur ou la largeur en est l’usage classique, mais elles peuvent aussi cibler la densité de pixels ou d’autres propriétés. Détecter l’OS et le type d’appareil peut aussi servir, car les caractéristiques de performance sur mobile diffèrent beaucoup de celles des ordinateurs.

J’espère que ces techniques vous seront utiles pour votre prochain projet. Bonne chance !


