Go to Hackademy website

Morphing et animation SVG

Victor Darras

Posté par Victor Darras dans les catégories front

Bonjour à tous, aujourd’hui je voudrais prendre un peu de temps pour vous expliquer une méthode bien pratique pour animer des SVG, notamment pour faire du morphing et rendre toujours plus renversantes vos landing pages.

TropLongPasLu : Faisons ensemble l’animation suivante !

See the Pen Card Icons Animation by Victor Darras (@victordarras) on CodePen.

Revenons dans un premier temps sur le SVG si vous le voulez bien. Format vectoriel par excellence, il est aussi très proche dans sa syntaxe de HTML (tous deux des déclinaisons de XML). Comme HTML, le SVG permet de définir un ensemble de balises (rect, circle, path…) afin de dessiner des formes plus ou moins complexes, de les combiner (masque, fusion…), les colorer (pleins, dégradés, motif) ou même gérer des filtres (flou, sépia, noir et blanc, etc.). La plupart de ces valeurs pouvant être modifiées, et le rendu SVG se faisant à la volée, profitons-en pour créer des animations.

Préparer l’animation

Pour faire simple nous allons commencer par animer une seule forme (un path). Un path étant composé de multiples points, il faut savoir que l’animation ne pourra se dérouler correctement que si le nombre de points reste identique d’une forme à l’autre, il faudra donc le prendre en compte quand nous dessinerons les différentes étapes de l’animation.

Prenons les différentes formes connues d’un jeu de cartes : le cœur, le pique, le carreau et le trèfle. Il paraît évident qu’ils n’ont pas besoin du même nombre de points pour être dessinés, par exemple :

lessDot.png

…il faudra donc ruser et ajouter des points ici et là…

moreDot.png

Un conseil : commencez par la forme la plus complexe pour n’avoir qu’à déplacer des points existants sur les formes plus simples. Ici j’ai donc commencé par le trèfle puis je l’ai déformé.

drawShape.gif

Une fois toutes ces formes mises en place, nous allons pouvoir définir l’animation qui les lie les unes aux autres.

Animer en HTML/SVG, simple et efficace

Attention, cela semble ne pas être supporté par IE/Edge

Une première technique, qui tire parti des meilleures possibilités de SVG, reste d’utiliser la balise <animate>. Celle-ci prend plusieurs attributs dont :

  • attributeName permet de définir l’attribut dont la valeur va changer ;
  • dur, correspond à la durée de l’animation ;
  • repeatCount nous donne le nombre d’occurrences de l’animation ;
  • values correspond aux différentes valeurs à appliquer à l’attribut dynamique.

Dans notre cas nous aurons donc besoin des valeurs suivantes :

  • repeatCount="indefinite" pour faire boucler l’animation ;
  • attributeName="d"d est l’attribut correspondant aux coordonnées d’un path SVG ;
  • une durée ;
  • et enfin une liste de différentes valeurs.

Séparées par un ; (attention à ne pas en mettre à la fin de la liste, ça ne fonctionnera pas), les différentes valeurs correspondent à chacun des SVG que nous avons créés plus tôt, plus précisément cette partie-là :

Capture%20d%E2%80%99e%CC%81cran%202018-07-02%20a%CC%80%2015.29.04_thumb_650.png

Nous aurons donc :

<animate
  id="animation"
  repeatCount="indefinite"
  attributeName="d"
  dur="5s"
  values="...;...;...;...">

Une fois la liste des valeurs remplie, vous pouvez afficher le SVG dans votre navigateur préféré et voir l’animation se lancer sous vos yeux ébahis.

See the Pen Full SVG Animation by Victor Darras (@victordarras) on CodePen.

Animer en CSS, verbeux et puissant (mais Chrome seulement…)

Je suis plutôt déçu par le résultat et j’aimerais plus de finesse, mais la balise <animate> ne suffira pas. J’ai maintenant deux choix pour affiner mon contrôle, utiliser du JavaScript ou du CSS. Pour ce premier exercice d’animation je vais rester au CSS qui utilise les même bases que nous avons vu, mais offre plus de souplesse.

Reproduisons à l’identique notre animation avec un peu de SVG et des @keyframes CSS.

Nettoyer le SVG

Nous n’avons plus besoin de définir les coordonnées (d) de path, nous les définirons en CSS. Nous déclarons juste un SVG avec un path vide.

<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 124 124">
  <path></path>
</svg>

Dessiner les formes, étapes par étapes

Pour chaque étape, nous allons définir une forme dans une keyframe avec une propriété d qui prendra pour valeur les coordonnées de la forme dans la valeur dans la fonction path('...') comme ceci :

@keyframes cardAnim {
  0%, 100% {
    fill: tomato;
    d: path('M53.8367971,98.0105931 C62.5709372,90.6149791 66.2112484,87.5325537 70.0435525,83.9893009 C72.7823134,81.4571109 75.6191301,78.6895642 80.4832815,73.9441868 C92.1537616,62.5586791 96.1292776,60.2840306 102.768438,50.2737766 C109.407598,40.2635227 109.562285,19.9893997 97.8949026,8.83310282 C86.2275205,-2.32319407 65.6287893,-3.34048116 53.8367971,12.6102024 C42.7337698,-3.12466085 21.4090627,-3.84487569 8.62341819,8.83310282 C-4.16222634,21.5110813 -0.873759373,43.5215692 6.53796897,53.1409641 C13.9496973,62.7603591 14.192282,61.619107 27.18463,73.9441868 C40.176978,86.2692666 40.176978,86.2692666 53.8367971,98.0105931 Z');
  }

  25% {
    fill: grey;
    d: path('M33.615073,120.257813 C41.8452148,120.257813 58.0737305,120.257812 66.2344717,120.257813 C54.7068699,105.270508 54.7068699,105.270508 54.7068699,86.1914063 C60.3429237,100.47998 89.8928659,98.6647688 97.3043495,78.7348633 C104.715833,58.8049578 92.8137868,46.6757813 78.4317909,30.3862305 C64.049795,14.0966797 64.049795,14.0966797 49.7691932,0 C36.8961464,14.0966797 36.8961464,14.0966797 21.5699745,30.3862305 C6.2438026,46.6757813 -6.36850208,62.7075195 3.49038463,80.6308594 C13.3492714,98.5541992 38.5890174,102.720703 45.0164402,86.1914063 C45.0164402,105.270508 45.0164402,105.270508 33.615073,120.257813 Z');
  }

  50% {
    fill: tomato;
    d: path('M47.0733712,115.058105 C47.4100427,114.390075 51.87634,105.790536 58.6510079,95.6299408 C61.3834707,91.5318141 75.754243,73.4853618 79.5956177,69.3575656 C82.3483693,66.3995627 86.3942962,62.4442739 91.7333984,57.4916992 C85.3540489,53.2612305 76.894088,44.8198242 66.3535156,32.1674805 C55.8129433,19.5151367 49.1927962,8.79264323 46.4930745,0 C41.8278874,10.0341797 34.9431516,20.7566732 25.8388672,32.1674805 C16.7345828,43.5782878 8.12162703,52.019694 0,57.4916992 C10.8533079,66.4956055 19.5749876,74.9956055 26.1650391,82.9916992 C36.0501163,94.9858398 38.2597656,98.434082 47.0733712,115.058105 Z');
  }

  75% {
    fill: grey;
    d: path('M35.3673641,112.529297 C40.8809183,112.529297 51.7540512,112.529297 67.9867628,112.529297 C60.301695,102.53776 56.459161,91.1822917 56.459161,78.4628906 C67.9867628,92.5771484 93.6134579,95.8808594 102.337091,73.9023438 C111.060724,51.9238281 87.0333798,35.1298828 71.9572079,40.6386719 C82.3312313,27.3115234 76.0675595,0 51.6290829,0 C27.1906063,0 20.5890438,28.1669922 31.4425595,40.6386719 C20.8243954,35.4130859 -4.19085428,48.1464371 0.603692268,70.0234375 C5.39823881,91.9004379 31.6515438,97.9189453 46.7687313,78.4628906 C47.9750977,97.1577148 42.9697266,105.318848 35.3673641,112.529297 Z');
  }
}

Vous remarquerez que j’ai mis les étapes 0% et 100% aux mêmes valeurs (pour faire une boucle complète), et que je change aussi de couleur de remplissage avec la propriété fill. Une fois les keyframes définies, il nous faut déclarer l’animation à utiliser pour l’élément path. Nous appelons d’abord les keyframes, suivies de la durée et du type de répétition (ici à l’infini) comme pour la version full SVG.

svg path {
  animation: cardAnim 5s infinite;
}

Maintenant j’aimerais faire en sorte de réduire le temps de transition pour pouvoir profiter au mieux du dessin de chaque étape (mieux distinguer les formes en somme). Je pourrais utiliser la valeur d’easing ease-in-out disponible par défaut, mais l’effet n’est pas assez saisissant, je vais donc préférer une fonction de courbe de Bézier :

svg path {
  animation: cardAnim 5s cubic-bezier(0.8, 0, 0.2, 1.2) infinite;
}

Pour comparer, voici la version cubic-bezier() à gauche et la version ease-in-out à droite :

animCompare.gif (c’est tout de même mieux, nan ?)

Ce qui au final devrait nous donner l’animation suivante :

See the Pen Card Icons Animation by Victor Darras (@victordarras) on CodePen.

C’est tout pour aujourd’hui, je n’ai évidemment fait qu’un tout petit tour des possibilités d’animation en SVG, je laisse à d’autres le soin d’être plus complets. J’espère vous avoir donné envie d’en voir plus, et d’expérimenter un maximum pour faire briller plus encore le web de 2018. On pourrait définir des points mieux pensés pour fluidifier l’animation, utiliser keyTimes ou keySplines pour simuler l’easing CSS, ou encore utiliser une deuxième animation SVG pour les couleurs :

<animate
  repeatCount="indefinite"
  attributeName="fill"
  dur="5s"
  values="#000;#F00;#000;#F00;#000"
  />

L’équipe Synbioz.
Libres d’être ensemble.

Articles connexes

Houdini, CSS by JS

21/03/2019

Bonjour à tous, bienvenue dans le monde magique de l’illusion et des faux-semblants, où un background peut souvent en cacher un autre. Que le rideau se lève le temps d’apercevoir ce qui se cache...

Architecture en trois tiers d'une application Vue.js

21/02/2019

Ça commence à faire un petit moment que je vous bassine avec Vue.js, et que je vous fais construire des single-page applications en s’appuyant dessus. Néanmoins, nous n’avons jamais réellement parlé...

Une bibliothèque pour gérer l'authentification avec Vue.js, partie 2 — en route vers HTTP

08/02/2019

À l’heure où j’écris ces lignes, il m’est difficile de prévoir le temps qu’il fera quand vous les lirez. Laissons donc cette fois-ci les considérations météorologiques de côté et replongeons-nous...

Dark mode et CSS

24/01/2019

Bonjour à tous, aujourd’hui un sujet (presque) d’actualité puisque nous allons parler du mode sombre de MacOS, mais surtout d’une nouvelle manière — assez radicale — de penser nos interfaces. Le...