Avec les transitions, nous avons appris à définir une valeur de départ et une valeur de fin.
Ces transitions sont parfaites pour animer par exemple l'état de survol d'un bouton ou le fait de passer d'une couleur A à une couleur B (en animant opacity
et pas background-color
, n'est-ce pas 🤨). Simple et efficace. Vous pouvez même changer le timing de votre transition.
Mais comment faire si on veut plus qu'un point A et un point B ?
Créez des étapes supplémentaires
Jetons un œil à la barre de progression que nous avions créée dans la partie 2, lorsque nous avons étudié transform-origin
:
Cette barre de chargement fait le travail. Mais… toutes les personnes ayant déjà téléchargé quelque chose sur Internet savent que les vitesses de connexion sont loin d'être constantes. La progression se fait par à-coups, entrecoupés de pauses et de ralentissements (ce qu'on préfère). Dans la courbe d'accélération de notre transition, le timing commence rapidement avant de s'estomper vers la fin, mais la progression suit toujours une trajectoire régulière.
Si nous voulons créer une barre de progression avec un ressenti plus authentique, nous pouvons utiliser la règle CSS @keyframes.
Alors que les transitions CSS ne font que passer d'une valeur à l'autre, les @keyframes nous permettent de concevoir des animations avec plusieurs étapes, et ainsi de créer des animations plus complexes et dynamiques.
Dans notre exemple, elle nous permet de créer des arrêts et des accélérations plus irréguliers, qui ressemblent davantage à une véritable barre de chargement.
Représentez-vous une course d'obstacles. Pour se rendre de la ligne de départ à la ligne d'arrivée, les concurrents doivent passer à travers des pneus, grimper par-dessus un mur et se balancer à travers une série de barres parallèles. Et entre deux obstacles, un point de contrôle, pour que les concurrents terminent tout le parcours, plutôt que de tricher en courant directement jusqu'à la ligne d'arrivée. Nous pouvons comparer les @keyframes à ces points de contrôle : ils jalonnent l'itinéraire de nos animations.
Définissez vos keyframes
Un keyframe CSS est défini par le pourcentage d'animation complété lorsque sa valeur est réalisée.
Cela veut dire que le début de notre animation en keyframes aurait une progression de 0 % et la propriété transformée une valeur de scaleX(0)
. La fin aurait une progression de 100 % et une valeur de scaleX(1)
. Maintenant que nous avons la première et la dernière étape, construisons notre premier ensemble de @keyframes !
Contrairement aux transitions, qui sont à usage unique et qui n'existent qu'à l'intérieur du sélecteur où elles ont été déclarées, les @keyframes sont disponibles globalement, donc n'importe quel sélecteur dans notre fichier CSS peut les utiliser. Et comme ils sont disponibles de manière globale, ils ne sont pas déclarés dans un sélecteur. Au lieu de cela, nous déclarons les @keyframes au niveau de base du fichier CSS, en utilisant l'opérateur @keyframes, suivi du nom de notre choix, entre accolades ouverte et fermée :
@keyframes progress-bar {
}
Lorsque nous utilisons la règle @keyframes, nous déclarons un ensemble de keyframes et nous lui donnons un nom, que nous pouvons utiliser pour appeler l'animation sur le sélecteur de notre choix. Maintenant que nous avons créé un ensemble @keyframes pour notre barre de progression, ajoutons nos keyframes de début et de fin.
Chaque keyframe est défini en utilisant son pourcentage, puis sa propre paire d'accolades qui nous permettent de définir les propriétés que nous souhaitons appliquer à ce stade de l'animation :
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
Nous avons maintenant une animation « progress-bar » (barre de progression) définie par la règle keyframes. Elle part d'une échelle scaleX()
de zéro qui finit à 1 au cours de son animation, tout comme la transition que nous avons construite dans la partie 2.
Imaginons que nous voulions des keyframes de début et de fin sans rien au milieu. Dans ce cas, pas besoin de pourcentage : nous pouvons définir les keyframes en utilisant les mots clés « from » et « to » :
@keyframes progress-bar{
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
Le mot clé « from » agit exactement de la même façon que le 0 %, et « to » correspond à 100 % : à vous de choisir en fonction de vos préférences/vos styles de codage établis.
On est plutôt pas mal partis…
Mais qu'est-ce qu'on fait maintenant ?
Passez à l'action
Nous pouvons ajouter cette animation dans le pseudosélecteur :active
de notre bouton. Cela vous rappelle quelque chose ? C'est ce que nous avions fait pour notre transition. Sauf qu'ici, nous la déclarons via les propriétés animation-name
et animation-duration
. animation-duration
ressemble beaucoup à transition-duration
, et accepte une valeur en ms (millisecondes) ou en s (secondes).
animation-name
, en revanche, est une nouvelle propriété. Elle nous permet d'assigner l'animation que nous venons de déclarer (avec les étapes from et to) à notre élément déclencheur ; ici la pseudoclasse :active
.
Ainsi, pour utiliser les keyframes de notre animation progress-bar, nous devons donner la valeur progress-bar à animation-name
:
.btn {
&:active {
& > .progress__bar {
transform: scaleX(1);
animation-name: progress-bar;
}
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
Maintenant, il nous suffit de reproduire la durée de notre transition. Pour cela, assignons à la propriété animation-duration
une valeur de 1 000 ms :
.btn {
&:active {
& > .progress__bar {
transform: scaleX(1);
animation-name: progress-bar;
animation-duration: 1000ms;
}
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
Bien joué !
Pour bien comprendre : les transitions s'animent lorsqu'on assigne une valeur à une propriété et que cette valeur change dans l'élément déclencheur. Pour les transitions, les valeurs doivent donc être assignées aux sélecteurs à l'intérieur de notre code.
Les animations @keyframes sont un peu différentes. Lorsque animation-name
et animation-duration
sont assignés à un sélecteur, les propriétés et valeurs contenues dans chaque keyframe sont appliquées pendant toute la durée de l'animation.
Cela signifie que nous n'avons pas besoin de nous soucier de régler la valeur de scaleX()
comme nous l'avions fait avec notre transition sur la barre de progression. Nous n'avons cependant pas besoin de la supprimer. En cas de conflit entre les propriétés/valeurs CSS d'une valeur assignée et d'une valeur avec keyframe, le CSS privilégie la valeur déclarée dans le keyframe.
Même si nous n'en avons pas besoin, pour des raisons de clarté, voyons comment supprimer transform de la pseudoclasse :active
:
.btn {
&:active {
& > .progress__bar {
transform: scaleX(1);
animation-name: progress-bar;
animation-duration: 1000ms;
}
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
Et voilà, on est prêts !
Heu… vraiment ? Comme pour les transitions, il est possible d'utiliser une seule propriété d'animation pour définir son nom, sa durée, etc. Un peu de ménage s'impose pour simplifier notre code !
.btn {
&:active {
& > .progress__bar {
animation: progress-bar 1000ms;
}
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
100% {
transform: scaleX(1);
}
}
Voyons voir comment se porte notre nouvelle barre de progression avec keyframes :
Où est-elle passée ?! Elle s'anime comme on voulait... mais ensuite elle disparaît ?
Nous reviendrons plus en détail sur les différences entre les transitions et les animations réalisées avec @keyframes dans le chapitre suivant. Mais pour l'instant, sachez simplement que les deux se comportent différemment.
Décomposez les différents keyframes
Nous avons une barre de progression animée qui passe directement de 0 % à 100 %. Elle ressemble bien à notre transition. Mais nous voulions complexifier l'animation en ajoutant quelques keyframes ici et là. Pour cela, quels pourcentages devons-nous choisir ? Et quelles valeurs devons-nous leur attribuer ? Utilisons comme modèle la courbe d'accélération de notre transition de barre de progression originale :
Sur l'axe X, nous avons le pourcentage de progression de l'animation, de notre point de départ à 0 % à 100 % tout à droite. Et sur l'axe Y, nous avons la valeur de scaleX()
de 0 en bas à 1 en haut.
Si nous devions choisir un point le long de la courbe d'accélération, sa coordonnée X pourrait servir de valeur en pourcentage des keyframes, et sa coordonnée Y de valeur pour scaleX()
:
Choisissons trois points le long de la courbe que nous définirons comme keyframes. Puisque nous voulons décomposer un peu l'animation de façon à la rendre plus naturelle, essayons de choisir ces points à intervalles aléatoires sur l'axe des X. Quelque chose comme cela pourrait marcher :
Maintenant que nous avons des valeurs avec lesquelles nous pouvons travailler, replongeons-nous dans nos keyframes ! Pour les créer, nous allons prendre la coordonnée X de chaque point, la transformer en pourcentage pour chacun de nos nouveaux keyframes, et utiliser la coordonnée Y comme valeur pour la valeur de scaleX(), de cette façon :
.btn {
&:active {
& > .progress__bar {
animation: progress-bar 1000ms;
}
}
}
@keyframes progress-bar {
0% {
transform: scaleX(0);
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
}
100% {
transform: scaleX(1);
}
}
Voyons comment l'animation s'affiche à l'écran avec nos nouveaux keyframes :
La barre se remplit avec un profil similaire à notre transition, mais chaque fois que l'animation arrive à un keyframe, il y a un léger ralentissement dans sa progression. On approche bien du sentiment de vraiment charger quelque chose.
Animez plusieurs propriétés
Nous avons donc une barre de progression un peu plus authentique. Ajoutons maintenant encore un peu plus de complexité. Au-delà de sa progression de gauche à droite, nous aimerions aussi que l’opacité de notre animation change, pour qu'elle évolue d'un vert translucide à un joli vert menthe, au fur et à mesure que la barre se remplit. Lorsque nous créons des @keyframes CSS, nous ne sommes pas limités à une seule propriété. Bien au contraire ! Nous pouvons assigner à chaque keyframe autant de propriétés que nous le souhaitons.
Pour ajouter des propriétés supplémentaires à un keyframe, il suffit de les ajouter dans nos accolades, comme nous le ferions avec un sélecteur CSS standard. Pour notre animation de couleur, nous pouvons configurer notre premier keyframe pour que la barre ait une opacité de 10 % au début de l'animation :
@keyframes progress-bar{
0% {
transform: scaleX(0);
opacity: .1;
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
}
100% {
transform: scaleX(1);
}
}
Nous avons réglé l'opacité à 10 % dans le premier keyframe. Mais rien n'est précisé dans les suivants quant à l'opacité. On peut supposer que la couleur de la barre restera à 10 % d'opacité pendant le reste de l'animation.
Voyons voir ce que ça donne dans le navigateur :
… Ce n'est pas du tout le cas !
Bien qu'il n'y ait pas d'autres keyframes pour l'opacité, la barre repasse bien à 100 % d'opacité au cours de l'animation.
Mais pourquoi ?
Nous n'avons pas précisé de valeur d'opacité dans les autres keyframes. Le navigateur va donc chercher la valeur d'opacité dans le sélecteur. Or, nous n'avons déclaré aucune valeur de manière explicite non plus dans .progress__bar.
Le navigateur prend donc la valeur par défaut de 1 pour l'opacité.
Testons cela. Assignons une valeur de 0 à opacity dans le sélecteur .progress__bar
et augmentons l'opacité de notre premier keyframe à 50 % :
.progress {
&__bar {
opacity: 0;
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
opacity: .5;
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
}
100% {
transform: scaleX(1);
}
}
Maintenant, notre barre devrait commencer à 50 % et s'animer pour devenir complètement transparente à la fin de l'animation :
Sans keyframe de départ, le navigateur démarrera l'animation avec la valeur dans le sélecteur, tout comme il le fait à la fin d'une animation si nous ne fournissons pas de keyframe de fin. Donc, si nous devions seulement fixer la valeur d'opacité à un pourcentage intermédiaire, comme cela :
.progress {
&__bar {
opacity: 0;
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
opacity: 1;
}
100% {
transform: scaleX(1);
}
}
Notre barre commence et se termine désormais avec la valeur d'opacité que nous avons assignée dans .progress__bar
, qui est zéro :
Nous sommes d'accord là-dessus : une barre de progression entièrement transparente ne constitue pas vraiment la meilleure expérience utilisateur.
Assignons donc une valeur d'opacité de 1. Mais, cette fois-ci, plutôt que d'attendre que l'animation soit complètement terminée pour devenir opaque, fixons le pourcentage de keyframe à 85 % :
.progress {
&__bar {
opacity: 0;
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
}
85% {
opacity: 1;
}
100% {
transform: scaleX(1);
}
}
Maintenant notre barre devrait passer 85 % de la durée de l'animation à remplir l'opacité. Allons vérifier cela :
Eh bien... elle passe bien 85 % de l'animation à augmenter l'opacité de la barre, mais ensuite elle passe les 15 % de l'animation finale à revenir à une barre complètement transparente. Ce n'est pas exactement ce que nous espérions...
Plutôt normal en fait : nous n'avons toujours pas de valeur pour la propriété d'opacité à animer entre 85 % et 100 %, donc le navigateur passe les 15 derniers pourcents de l'animation à repasser à la valeur assignée à .progress__bar
, qui est toujours 0. Nous devons donc définir un dernier keyframe pour la propriété d'opacité, avec une valeur fixée à 1.
Nous avons déjà créé un keyframe avec un pourcentage de 100 % pour notre propriété transform
. Nous pourrions ajouter la propriété d'opacité à ce keyframe, mais que se passerait-il si nous décidions que nous voulions que notre opacité finale soit de 85 % au lieu de 100 % ? Ensuite, nous devons modifier la valeur d'opacité dans plusieurs emplacements. Cela signifie plus de travail 😭, mais aussi des risques supplémentaires d'oubli et d'erreur.
Jusqu'à présent, nous avons fixé un pourcentage unique pour chaque keyframe, mais nous pouvons attribuer plusieurs pourcentages à un keyframe. En ajoutant plusieurs pourcentages à un keyframe, le navigateur appliquera son contenu à chaque pourcentage d'animation. Il suffit de les séparer par des virgules :
.progress {
&__bar {
opacity: 0;
}
}
@keyframes progress-bar{
0% {
transform: scaleX(0);
}
17% {
transform: scaleX(.18);
}
24% {
transform: scaleX(.4);
}
46% {
transform: scaleX(.81);
}
85%,100% {
opacity: 1;
}
100% {
transform: scaleX(1);
}
}
Et maintenant, si nous reprenons notre barre de progression pour la tester à nouveau, les choses devraient ressembler à ce à quoi nous nous attendions :
PARFAIT ! Maintenant l'opacité de notre barre de chargement est totale à 85 % et le reste jusqu'à la fin de l'animation.
Alors, vous avez testé chez vous ? 🤓
En résumé
les animations @keyframes nous permettent de construire des animations plus complexes en créant plusieurs étapes pour les propriétés tout au long de l'animation ;
les keyframes CSS sont instanciées à l'aide de la règle @keyframes suivie d'un nom pour l'ensemble des keyframes :
@keyframes example-frames {...} ;
chaque keyframe peut être établi en utilisant comme valeur le pourcentage d'animation réalisé :
33% {...} ;
si vous n'avez besoin que d'un keyframe de début et de fin, les mots clés « from » et « to » peuvent être utilisés à la place de 0 % et 100 % respectivement ;
si aucun keyframe de début ou de fin n'est fourni, l'animation commence et/ou se termine avec les valeurs de propriété assignées au sélecteur. Si aucune valeur n'est explicitement assignée dans le sélecteur, c'est la valeur par défaut qui est choisie ;
une animation définie par la règle @keyframes peut contenir différents keyframes avec des propriétés distinctes ;
plusieurs pourcentages peuvent être assignés à un seul keyframe. Les valeurs définies dans ce keyframe seront appliquées à ces pourcentages dans l'animation ;
les propriétés et valeurs d'un ensemble de keyframes remplaceront les valeurs de propriétés attribuées à un sélecteur au cours de l'animation.
Vous avez maintenant découvert les keyframes : bravo ! Dans le prochain chapitre, nous allons nous pencher plus en détail sur l'implémentation d'animations @keyframes dans notre CSS, sur les différences fondamentales avec les transitions. Nous verrons également comment pousser nos animations encore plus loin avec d'autres propriétés d'animation @keyframes. À tout de suite !