Dans la série du 25e anniversaire des Trucsweb, nous avons vu la transition et la transformation CSS3. Aujourd’hui, nous verrons un tutoriel que je veux faire depuis longtemps sur les animations CSS3.
Les animations CSS3 se retrouvent un peu partout depuis quelques années grâce à son extraordinaire pouvoir d’attraction. Personnellement, je ne suis pas un grand amateur de mouvement excessif. C’est loin d’être indispensable et on conseille d’ailleurs fortement un usage parcimonieux. Un peu d’animation ne fait pas de tort et peu même aider à distinguer certains éléments d’une page Web, améliorer l’ergonomie ou même aider à la compréhension. Par contre, trop d’animation peut au contraire perturber la lecture et distraire l’usager du propos.
D’autre part, il ne faut pas sous-estimer le pouvoir d’attraction et le prestige qu’apportent les animations. Exactement comme une belle photographie qui sublime la première impression en consultant un site Web, l’animation donne du professionnalisme au site Web. Si je demande à des internautes leur avis sur un site Web, vous pouvez être sûr qu’un site avec des animations raflera la palme et relèguera aux oubliettes la concurrence !
Il existe plusieurs façons de déclencher une animation, par défaut d’entrée de jeu dès le chargement de la page. On peut la faire boucler par exemple à l’infinie. Mais on peut aussi la déclencher après le survol de la souris. La plus populaire, et il existe un tas de librairies, c’est activer une animation suite au défilement de la page ou à un autre événement en JavaScript. C’est-à-dire, que l’animation débute seulement si l’usager fait défiler la page jusqu’à l’élément animé en question.
Tout élément HTML peut être animé. La page au complet, par exemple un fondu à l’ouverture de la page. Non seulement ça permet une navigation fluide, mais en plus, ça évite de voir une page à moitié construite si elle n’est pas tout à fait chargée. On peut animer une section, mais aussi un élément comme une image, un bouton ou même un simple pictogramme. Des les exemples suivants, le titre de la page...
Règle @keyframes
Beaucoup plus simple qu’en apparence, l’animation CSS est construite en deux étapes. La première est une classe qui appelle une seconde classe qui est en fait une série d’images clés (keyframes) pour définir l’état de l’animation dans un temps donné. L’animation passera progressivement du style actuel au nouveau style à un certain moment. C’est-à-dire, les changements de propriétés de l’élément entre le départ (0%) et la fin (100%) de l’animation.
C’est ce qui fait la force des animations CSS. C’est possible de définir un nombre quasi illimité de keyframes
. La première étape consiste donc à définir les keyframes
:
<style>
@keyframes monExample1 {
from {margin-left: 3rem;}
to {margin-left: 0rem;}
}
</style>
La deuxième étape, lier une classe au @keyframes
:
<style>
.monAnimation1 {
margin-left: 0;
animation-name: monExample1;
}
</style>
<h1 class="monAnimation1">Mon titre animé</h1>
Même si c’est de plus en plus compatible, je conseille au moins le préfixe -webkit-
pour les navigateurs Google Chrome, Opera et Apple Safari.
@keyframes monExample1 {
from {margin-left: 3rem;}
to {margin-left: 0rem;}
}
@-webkit-keyframes monExample1 {
from {margin-left: 3rem;}
to {margin-left: 0rem;}
}
.monAnimation {
margin-left: 0;
animation-name: monExample1;
-webkit-animation-name: monExample;
animation-duration: 2s;
-webkit-animation-duration: 2s;
}
<h1 class="monAnimation1">Mon titre animé</h1>
Les propriétés animation-duration: 2s
et animation-iteration-count
Dans le code précédent, j’ai ajouté la propriété animation-duration: 2s
qui définit la durée de l’animation. Sans elle, il n’y aura pas d’animation (ou elle sera effectuée en 0 seconde!). Même chose avec la propriété animation-iteration-count
. Dans l’exemple suivant, j’ai volontairement ajouté une propriété pour boucler (loop) l’animation à l’infinie animation-iteration-count: infinite
qui spécifie le nombre de fois qu’une animation doit s’exécuter. Sinon, l’animation se produit une fois la page chargée et donc l’animation serait déjà terminée !
Pourcentage
Ajoutons maintenant des images-clé à 25%, 50% et 75% pour changer la couleur :
<style>
@keyframes monExample4 {
from {color: black;margin-left: 12rem;}
25% {
color: blue;
}
50% {
color: red;
}
75% {
color: yellow;
}
to {color: black;margin-left: 0rem;}
}
@-webkit-keyframes monExample4 {
from {color: black;margin-left: 12rem;}
25% {
color: blue;
}
50% {
color: red;
}
75% {
color: yellow;
}
to {color: black;margin-left: 0rem;}
}
.monAnimation4 {
margin-left: 0;
color: black;
animation: 4s infinite alternate monExample4;
-webkit-animation: 4s infinite alternate monExample4;
}
</style>
Résultat :
Mon titre animé
Pas une seule ligne de JavaScript encore. Simple, mais puissant, car c’est possible de cumuler plusieurs animations.
Propriété de raccourcie animation
Exactement le même code, mais en une seule instruction :
@keyframes monExampl3 {
from {margin-left: 3rem;}
to {margin-left: 0rem;}
}
@-webkit-keyframes monExample3 {
from {margin-left: 3rem;}
to {margin-left: 0rem;}
}
.monAnimation3 {
margin-left: 0;
animation: 3s infinite monExample3;
-webkit-animation: 3s infinite monExample3;
}
<h1 class="monAnimation3">Mon titre animé</h1>
<style>
animation-name: monAnimation1, monAnimation2, monAnimation3;
animation-duration: 5.2s, 5s, 1s;
animation-iteration-count: 3, 1, 5;
</style>
Notez cette fois de l’utilisation de animation-iteration-count
avec un chiffre au lieu de infinite
.
Autres propriétés
La propriété animation-direction
Exécuter l’animation en avant, en arrière ou en cycles alternés.
normal
- L’animation est jouée normalement (vers l’avant). C’est par défaut
reverse
- L’animation est jouée en sens inverse (vers l’arrière)
alternate
- L’animation est d’abord jouée en avant, puis en arrière
alternate-reverse
- L’animation est d’abord lue en arrière, puis en avant
Dans cet exemple, le animation-direction: alternate
inverse l’animation :
Résultat :
Mon titre animé
La propriété transition-timing-function
La propriété transition-timing-function
spécifie la « courbe » de vitesse de l’effet de transition. C’est-à-dire quelle module la transition en fonction du début et de la fin de la transition.
ease
- spécifie un effet de transition avec un démarrage lent, puis rapide, puis se termine lentement (par défaut) ;
linear
- spécifie un effet de transition avec la même vitesse du début à la fin ;
ease-in
- spécifie un effet de transition avec un démarrage lent ;
ease-out
- spécifie un effet de transition avec une fin lente ;
ease-in-out
- spécifie un effet de transition avec un début et une fin lents ;
cubic-bezier(n,n,n,n)
- vous permet de définir vos propres valeurs dans une fonction « cubic-bezier ».
Par défaut, les exemples précédents on une « courbe » ease
, soit lent => rapide => lent. Voici le même exemple avec la valeur ease-in-out
.
Résultat :
Mon titre animé
La propriété animation-fill-mode
Spécifier le mode de remplissage pour une animation.
aucun
- valeur par défaut. L’animation n’appliquera aucun style à l’élément avant ou après son exécution
vers
l’avant - L’élément conservera les valeurs de style définies par la dernière image clé (dépend de l’animation-direction et de l’animation-iteration-count)
vers
l’arrière - L’élément obtiendra les valeurs de style définies par la première image clé (dépend de la direction de l’animation) et les conservera pendant la période de retard de l’animation
les deux
- L’animation suivra les règles pour l’avant et l’arrière, étendant les propriétés de l’animation dans les deux sens
La propriété animation-delay
Spécifie un délai pour le démarrage d’une animation.
Exemples concrets
On a seulement entrevu l’animation d’une marge, on peut aussi utiliser des transitions, des transformations ! À commencer par la transition d’une page Web. Vous pouvez animer la page au complet body
ou seulement le contenu main
. l’effet est tout aussi bon ! Je vais appliquer un fondu de zéro à 100% à l’aide de la propriété opacity
!
Chargement de la page
<style>
@keyframes fondu-entrant {
from {opacity: 0;}
to {opacity: 1;}
}
@-webkit-keyframes fondu-entrant {
from {opacity: 0;}
to {opacity: 1;}
}
body {
animation: fondu-entrant 2s;
-webkit-animation: fondu-entrant 2s;
}
</style>
Wow, on peut toujours utilisé les librairies Wow et Animate.css pour faire la même chose. Noter que je n’ai pas créé de classe dans cet exemple. J’ai carrément utilisé le sélecteurbody
. Vous pourriez appliquer une animation à toutes les images de la page en ciblant la balise img
par exemple.
Texte du héraut* (hero)
Le plus simple c’est d’animer le texte qu’on retrouve souvent en haut de la page dans le héraut. Pour la simple et bonne raison qu’on a pas besoin de boucle pour voir l’animation ni de JavaScript pour provoquer l’animation au bon moment.
* Traduction libre : héraut au lieu du terme anglais « hero », c’est l’Annonciateur de la venue de la page web ! » ; - )
<style>
.animer {
/* Durée et mode appliqué à toutes mes animations */
animation-duration: 1s;
-webkit-animation-duration: 1s;
animation-fill-mode: both;
-webkit-animation-fill-mode: both;
}
/* Fondu entrant vers le bas */
@-webkit-keyframes fondu-entrant-bas {
0% {-webkit-transform: translateY(-30px);}
100% {-webkit-transform: translateY(0);}
0% {opacity: 0;}
100% {opacity: 1;}
}
@keyframes fondu-entrant-bas {
0% {transform: translateY(-30px);}
100% {transform: translateY(0);}
0% {opacity: 0;}
100% {opacity: 1;}
}
.fondu-entrant-bas {
animation-name: fondu-entrant-bas;
-webkit-animation-name: fondu-entrant-bas;
}
/* Fondu entrant vers le haut */
@-webkit-keyframes fondu-entrant-haut {
0% {-webkit-transform: translateY(30px);}
100% {-webkit-transform: translateY(0);}
0% {opacity: 0;}
100% {opacity: 1;}
}
@keyframes fondu-entrant-haut {
0% {transform: translateY(30px);}
100% {transform: translateY(0);}
0% {opacity: 0;}
100% {opacity: 1;}
}
.fondu-entrant-haut {
animation-name: fondu-entrant-haut;
-webkit-animation-name: fondu-entrant-haut;
}
</style>
<section class="position-relative" style="background-color:#fff">
<h2 class="animer fondu-entrant-bas">Le titre de ma page</h2>
<p class="lead animer fondu-entrant-haut">Mon sous-titre de la page</p>
<p class="animer fondu-entrant-bas"><a id="refairelanimation" href="#" role="button" class="bouton">Reproduire l’animation</a></p>
</section>
Évidement, l’animation est terminée depuis longtemps. J’ai donc ajouté un bouton pour l’activer en JavaScript.
Exemple :
Le titre de ma page
Mon sous-titre de la page
Cliquez pour reproduire l’animation
JavaScript
Utiliser un sélecteur pour déclencher une animation, par exemple un bouton réactif monBouton:hover {...}
ou activer l’animation à partir d’événements JavaScript. L’exemple plus haut utilise d’ailleurs un écouteur pour retirer l’animation et un bouton pour provoquer l’animation simplement en basculant d’une classe à l’autre.
L’exemple suivant détecte l’animation du titre de l’exemple plus haut :
<script>
var oElement = document.getElementById("oMonTitre");
// Début de l'animation
oElement.addEventListener("animationstart", maFonction, false);
// Fin de l'animation
oElement.addEventListener("animationend", maFonction, false);
// Répétition de l'animation
oElement.addEventListener("animationiteration", maFonction, false);
function maFonction(event) {
console.log(`Type de l'événement : ${event.type}`);
console.log(`Durée écoulée : ${event.elapsedTime}`);
}
</script>
Animation après défilement (animation on scroll)
Si on applique une animation à un élément hors de la partie visible de la page, il y a de fortes chances qu’on ne puisse voir l’animation en question, car elle aura déjà été exécutée. On peut ajouter un délai, mais si l’usager reste longtemps en haut de la page, c’est peine perdue. Il faut donc absolument un JavaScript pour détecter l’élément à animer suite au défilement de la page.
- On capture l’événement
scroll
; - On appelle la fonction « twDefillement » ;
- On ajoute la classe
active
pour déclencher l’animation ; Ou on retire la classe
active
pour annuler l’animation.
NOTE : la transform: translateX(-100vw);
négative positionne l’élément à « -100vh ». C’est-à-dire à 100vh à gauche. 100vh = la largeur de l’écran, ou plutôt du « viewport ». En d’autres mots, à l’extérieur de la page à gauche. Notez que c’est beaucoup, mais plus vite, on pourrait facilement diviser par deux cette valeur et du coup ralentir l’animation. Même chose avec transform: translateX(100vw);
, mais cette fois positif donc à droite de l’écran.
<style>
/* Classe par défaut qui spécifie quelques attributs de base, mais */
/* surtout, qui servira à identifier dans le DOM nos éléments à animer */
.defilement {
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
/* Glisser vers la gauche */
/* L'élément passe de l'extérieur de la page */
/* (-100% de la largeur de la page à 0) */
@-webkit-keyframes glisser-gauche {
0% {transform: translateX(-100vw);}
100% {transform: translateX(0);}
}
@keyframes glisser-gauche {
0% {transform: translateX(-100vw);}
100% {transform: translateX(0);}
}
/* D'entré de jeu, sort l'élément de l'écran (à gauche) */
.defilement-glisser-gauche {
transform: translateX(-100vw);
}
/* La classe active permet d'activer l'animation */
.defilement-glisser-gauche.active {
-webkit-animation-name: glisser-gauche;
animation-name: glisser-gauche;
}
/* Glisser vers la droite */
/* L'élément passe de l'extérieur de la page */
/* (100% de la largeur de la page à 0) */
@-webkit-keyframes glisser-droite {
0% {transform: translateX(100vw);}
100% {transform: translateX(0);}
}
@keyframes glisser-droite {
0% {transform: translateX(100vw);}
100% {transform: translateX(0);}
}
/* D'entré de jeu, sort l'élément de l'écran (à droite) */
.defilement-glisser-droite {
transform: translateX(100vw);
}
/* La classe active permet d'activer l'animation */
.defilement-glisser-droite.active {
-webkit-animation-name: glisser-droite;
animation-name: glisser-droite;
}
/* Fondu entrant */
@-webkit-keyframes fondu-entrant {
0% {opacity: 0;}
100% {opacity: 1;}
}
@keyframes fondu-entrant {
0% {opacity: 0;}
100% {opacity: 1;}
}
/* Fondu entrant */
.defilement-fondu-entrant {
opacity: 0;
}
.defilement-fondu-entrant.active {
-webkit-animation-name: fondu-entrant;
animation-name: fondu-entrant;
}
</style>
<script>
// Variable pour animer les éléments une seule fois ou infini
var bRepete = true;
// Fonction twdefilement()
function twdefilement() {
// Détecte tous les éléments avec la classe .defilement
var oDefilement = document.querySelectorAll(`.defilement`);
// Boucle tous les éléments avec la classe .defilement
for (var i = 0; i < oDefilement.length; i++) {
// Hauteur de la fenêtre
var fenetreHauteur = window.innerHeight;
// Position de l’élément par rapport à la fenêtre d’affichage
var elementHaut = oDefilement[i].getBoundingClientRect().top;
// Hauteur de l’élément / 2
var elementVisible = oDefilement[i].parentElement.parentElement.clientHeight/2;
// Si l’élément est visible, on l’anime, sinon on ne l’anime pas
if (elementHaut < fenetreHauteur - elementVisible) {
oDefilement[i].classList.add(`active`);
} else {
// Seulement si on veut répéter l’animation plus d’une fois
if (bRepete) {
oDefilement[i].classList.remove(`active`);
}
}
}
}
// Détecte le défilement de la page et appelle la fonction twDefilement
window.addEventListener(`scroll`, twdefilement);
// Provoque l’événement au chargement de la page
twDefilement();
</script>
<main class="container mt-5">
<div class="row mt-5">
<div class="col-12 col-md-6 col-lg-4 offset-lg-1 d-flex align-items-center p-5 p-lg-0">
<img src="image.jpg" class="img-fluid defilement defilement-glisser-gauche">
</div>
<div class="col-12 col-md-6 col-lg-4 offset-lg-1 d-flex align-items-center">
<p class="defilement defilement-fondu-entrant px-5 px-sm-0">Lorem ipsum dolor sit amet...
</div>
<hr class="w-50 mx-auto mt-5 d-flex align-items-center">
</div>
<div class="row mt-5">
<div class="col-12 col-md-6 col-lg-4 offset-lg-1 d-flex align-items-center">
<p class="defilement defilement-fondu-entrant px-5 px-sm-0">Lorem ipsum dolor sit amet...
</div>
<div class="col-12 col-md-6 col-lg-4 offset-lg-1 d-flex align-items-center p-5 p-lg-0">
<img src="image.jpg" class="img-fluid defilement defilement-glisser-droite">
</div>
</div>
</main>
Librairies gratuites
Les librairies requièrent du JavaScript, mais de plus en plus sans jQuery, ce qui est une très bonne chose. Plus ou moins lourde, c’est librairie on le même défaut que les cadriciels, beaucoup de code inutile.
Animate.css - Just-add-water CSS animations par Daniel Eden and friends
Animate.css est une librairie d’animation d’élément HTML. Simple et lège, elle est utilisée depuis des années dans des milliers de gabarits Web. Souvent en combinaison avec la librairie wow.js.Sur Github
Librairies d’animation de défilement (Scroll animation librairie)
AOS - Animate On Scroll Library - par Michał Sajnóg
C’est la librairie la plus populaire pour animer des éléments en fonction du défilement de la page.Sur Github
AOE.js Animate On entrance (AOE) scroll animation library
La nouvelle librairie AOE est une imitation de l’original AOS.
Sur Github
Wow.js - Animation on scroll combiné avec animation.css par Matt Aussaguel (Thomas Grainger)
Wow est une des premières librairies gratuites, qui doit être combinées avec Animate.css, que j’ai beaucoup utilisé. Un peu dépassée par l’excellent AOS de l’aveu même de Thomas Grainger.Sur Github
Conclusion
Références
- Ten tips for better CSS transitions and animations - Josh Collinsworth
- CSS Animations - W3C
- Utiliser les animations CSS - MDN
- Transition CSS - Trucsweb.com
- Transformation CSS - Trucsweb.com
- Can I use « @keyframes » - Caniuse.com
- Animate.css - Daniel Eden and friends
- AOS - par Michał Sajnóg
- AOE.js
- Wow.js - Matt Aussaguel (Thomas Grainger)
Résultat :
Mon titre animé