La Cascade

Un peu de tout sur CSS, HTML, SVG et JS,traduit du web anglophone
Rechercher

Animer un SVG avec CSS

par Chris Coyier, 23 avril 2014, css, svg, animation, article original paru le 1er avril 2014 dans CSS-Tricks

Chris Coyier s'est amusé à créer une petite animation SVG en CSS, sans passer par des bibliothèques compliquées. C'est fait maison, simple, efficace et clair comme toujours avec Chris.


Il existe plusieurs façons d'animer une image svg, depuis la balise animate jusqu'aux bibliothèques comme Snap.svg ou SVG.js. Nous allons essayer autre chose ici, en utilisant SVG à l'intérieur de notre HTML et en animant les parties de l'image avec CSS.

Je me suis amusé avec ça dernièrement, Wufoo souhaitant rafraîchir le graphisme de ses pubs sur CSS-Tricks. Voici une idée de ce que nous allons réaliser :

voir Wufoo SVG Ad de Chris Coyier dans CodePen

1. Concevoir la pub

Ça va ressembler à une leçon de dessin sommaire, mais notre objectif étant l'animation, nous allons passer sur le reste vite fait. Je souhaitais une pub super simple à partir de leur logo classique, de leurs couleurs etc., auquels j'ajouterais une touche personnelle.

  1. Faire sauter les lettres dans la page. Wufoo est un mot marrant, les lettres peuvent s'amuser un peu.
  2. Dans le bon vieux temps, on faisait des T-Shirts avec un dinosaure devant, et derrière il y avait "Fast. Smart. Formidable", des caractéristiques que Wufoo partage avec les dinosaures, sans parler du jeu de mots sur FORMidable… (NdT: Wufoo est un outil permettant d'élaborer des formulaires, form en anglais). Faisons apparaître et disparaître ce slogan.
  3. Pour aller au bout de notre idée, faisons apparaître la tête d'un dinosaure qui surgit, intrigué, des profondeurs, et disparaît à la vitesse de l'éclair, laissant le mot "fast" s'afficher.

J'ai mis tout ça sur Illustrator :

des images conçues sur illustrator

Remarquez que le logo et le texte du slogan sont des formes vectorielles, leur rendu en <path> (chemins) SVG sera très simple.

Le texte "Fast." est laissé en tant que texte dans Illustrator. Quand je le sauvegarderai, il sera conservé sous la forme d'élément <text>.

2. Sauvegarder en format SVG

Illustrator peut le sauvegarder directement en format SVG :

comment sauvegarder sur illustrator

Vous pouvez ouvrir ce fichier SVG dans votre éditeur de texte et voir le code SVG :

le contenu complexe du fichier svg

3. Nettoyer le SVG, lui ajouter des classes

Pour le nettoyage, vous pouvez utiliser SVGO qui optimisera le fichier, retirera le DOCTYPE et toutes les choses inutiles. Mais ce qui est plus important ici, c'est de donner des classes aux différentes formes, afin que nous puissions les sélectionner dans notre CSS.

//CSS

<svg version="1.1" id="wufoo-ad" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">

  <!-- background -->
  <rect class="wufoo-background" fill="#D03E27" width="400" height="400" />

  <!-- logo letters -->
  <path class="wufoo-letter" fill="#F4F4F4" d="M60.858,129...." />
  <path class="wufoo-letter" fill="#F4F4F4" d="..." />
     <!-- etc -->

  <!-- dinosaur -->
  <g class="trex">
     <path ... />
     <path ... />
  </g>

</svg>

4. Insérer le SVG

Vous pouvez copier-coller ce SVG dans votre HTML, à l'endroit où vous voulez que la pub apparaisse. Si vous ne voulez pas que ça embrouille votre template, vous pouvez aussi faire quelque chose comme :

//HTML

<aside class="sidebar">

   <div class="module module-ad">

       <?php include("ads/wufoo.svg"); ?>

   </div>

   ...

5. Animer !

Nos formes sont maintenant dans le DOM, nous pouvons les cibler et leur appliquer un style comme à n'importe quel autre élément HTML. Allons-y.

Pour commencer, disons que cette animation doit avoir une durée totale de 10 secondes.

Fade in/out des mots

Le premier événement est l'apparition des mots Fast. Smart. Formidable. Chaque mot sera affiché pendant une seconde. Nous allons donc réaliser une animation dans laquelle chaque mot apparaît pour une durée égale à 10% du temps total :

//CSS

@keyframes hideshow {
  0% { opacity: 1; }
  10% { opacity: 1; }
  15% { opacity: 0; }
  100% { opacity: 0; }
}

Puis ciblons le premier mot et fixons la durée de l'animation à 10 secondes (10% de cette durée = 1 seconde) :

//CSS

.text-1 {
  animation: hideshow 10s ease infinite;
}

Les deux mots suivants seront d'abord cachés (opacity: 0;) puis utiliseront exactement la même animation mais avec un délai, pour les faire partir successivement :

//CSS

.text-2 {
  opacity: 0;
  animation: hideshow 10s 1.5s ease infinite;
}
.text-3 {
  opacity: 0;
  animation: hideshow 10s 3s ease infinite;
}

La demie seconde supplémentaire entre chaque mot permet un fade out en douceur avant l'apparition du mot suivant.

Lettres bondissantes

Passons maintenant aux lettres de WUFOO et à leur petite danse :

les lettres de wufoo s'animent

L'astuce ici est de donner une durée de 5 secondes à notre animation, mais de la faire fonctionner dans un sens puis dans l'autre. De cette façon, elle correspond bien à notre durée totale de 10 secondes, elle se produit au milieu comme nous le souhaitons, et nous n'avons besoin de paramétrer qu'un seul sens.

Chaque lettre a un petit délai, décalé par rapport aux autres :

//SCSS

.wufoo-letter {
  animation: kaboom 5s ease alternate infinite;
  &:nth-child(2) {
    animation-delay: 0.1s;
  }
  &:nth-child(3) {
    animation-delay: 0.2s;
  }
  &:nth-child(4) {
    animation-delay: 0.3s;
  }
  &:nth-child(5) {
    animation-delay: 0.4s;
  }
}
@keyframes kaboom {
  90% {
    transform: scale(1.0);
  }
  100% {
    transform: scale(1.1);
  }
}

Pour abréger, j'ai écrit ce code en SCSS et sans y mettre les préfixes constructeurs.

Je trouve que la propriété animation-delay devrait pouvoir supporter de façon native une valeur aléatoire, ce serait sympa de voir un délai différent à chaque apparition.

Le dinosaure, enfin

Dès que les mots ont disparu, le dinosaure lève la tête. L'animal est construit avec de nombreux path, mais nous pouvons le cibler globalement grâce à l'attribut groupe <g> qui enveloppe tous ces chemins.

Pour animer une position, il est préférable d'utiliser translate et c'est ce que nous allons faire :

//CSS

@keyframes popup {
  0% {
    transform: translateY(150px);
  }
  34% {
    transform: translateY(20px);
  }
  37% {
    transform: translateY(150px);
  }
  100% {
    transform: translateY(150px);
  }
}

Nous voulons que cette animation "dure" 3 secondes, en fait elle dure 10 secondes mais vous n'en verrez que 3 secondes, car lorsque translateY(150px) se déclenche, le dinosaure est enfoui si profond que vous ne voyez rien. Aux alentours de 37% de cette animation (vers 3 secondes) vous le verrez apparaître lentement puis disparaître rapidement vers le bas.

Pour appliquer cette animation, nous devons nous assurer que :

  • Le dinosaure est invisible au départ.

  • L'animation comporte un délai, de façon à ce que la danse des lettres soit achevée.

      //CSS
    
      .trex {
        transform: translateY(150px);
        animation: popup 10s 6.5s ease infinite;
      }

Le dinosaure se cache à la dernière seconde lorsque le mot "Fast." revient à l'écran (parce que toutes les animations sont définies comme infinite ce qui les relance dès qu'elles sont terminées).

6. Une pub responsive et cliquable

Un avantage considérable de SVG est que la qualité de l'image est toujours impeccable quelle que soit la taille. Pour obtenir une image flexible qui conserve son ratio (même équilibre global des proportions), nous pouvons utiliser la bonne vieille technique de la boîte avec padding.

//HTML

<div class="wufoo-ad-wrap">
  <svg class="wufoo-ad">
     ...
  </svg>
</div>

//CSS

.wufoo-ad-wrap {
  height: 0;
  padding-top: 100%;
  position: relative;
}
.wufoo-ad {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

L'idée ici est que le "wrap" sera toujours un carré parfait, aux dimensions calculées à partir de sa largeur. Nous positionnons ensuite le SVG de façon absolue à l'intérieur de ce carré parfait, qui se redimensionnera avec bonheur.

Puisqu'il s'agit d'une pub, qui doit évidemment être cliquable, on pourrait utiliser <a href=""> à la place de <div> pour le contenant wrap, dans ce cas n'oubliez pas d'ajouter display: block.

La démo finale est ici.

Autres ressources externes

Articles de Chris Coyier traduits dans La Cascade

Voir la page de Chris Coyier et la liste de ses articles dans La Cascade.
Article original paru le 1er avril 2014 dans CSS-Tricks
Traduit avec l'aimable autorisation de CSS-Tricks et de Chris Coyier.
Copyright CSS-Tricks © 2014