Icône animée

Animer une icône au format SVG en CSS

Le SVG

De plus en plus de sites utilisent des icônes au format SVG, c’est un format sans perte et vectoriel, donc peut être agrandi ou rétréci à volonté. Le poids est très léger et c’est facile à animer. Et c’est justement ce qui m’intéresse !

Voici l’icône sur laquelle je vais travailler, c’est un graphiste qui bosse avec moi (Ugo) qui a eu la gentillesse de me la faire. Typiquement, cette icône représente le symbole de l’upload et je vais essayer de l’animer de telle sorte que les utilisateurs comprennent que c’est un téléchargement.

L'animation

Alors moi ce que je veux pour cette animation, c’est que la flèche tourne un tour et demi, voire un tout petit plus car j’aimerais bien simuler un ralentissement puis une animation inverse pour la remettre bien droite, à la bonne position. Je veux également animer la barre en-dessous en la décalant un peu vers le bas et en la remontant quand l’animation est terminée.

Je commence par construire la structure HTML, un span avec mon SVG à l’intérieur.

<span>
	<?php include "/img/ico-download.svg"; ?>
</span>

Pour gagner du temps, j’ai choisi de travailler avec du SASS et Compass !

Première chose, je cale mes éléments proprement, c’est-à-dire que je centre mon icône dans le wrapper, je donne une taille max au SVG et je définis une couleur au disque. Pour les deux paths du SVG, je leur ai attaché une classe, first et second, pour pouvoir les cibler facilement.

.download{
	text-align: center;
	span{
		display: inline-block;
		svg{
			max-width: 80px;
			@include transform-origin(50%,43%);
			path.first{
				@include transform-origin(50%,43%);
			}
			circle{
				fill:#d92b4b;
			}	
		}				
	}
}

Je crée les animations d’entrée et de sortie de la flèche via des @keyframes. Et là, tu peux voir l’énorme puissance de Compass et de SASS qui me permettent d’éviter d’écrire les préfixes pour les différents navigateurs.

Pour l’animation animation_ico_download_arrow, j’ai mis pas mal de temps à trouver le bon effet. L’animation est linéaire et se décompose facilement, elle se déplace d’un demi-tour, trois fois de suite (3 fois 180°). Je la fais encore tourner de quelques degrés pour la faire revenir sur une période assez longue, comme ça, il y a comme une sensation de « Oups je suis allé trop loin, j’dois revenir ». Quant à l’animation de sortie animation_ico_download_arrow_reverse, c’est exactement la même chose en sens inverse

L’animation du petit socle animation_ico_download_plinth est encore plus simple. Au début, je décale le socle vers le bas et à la fin de l’animation, je le remets à sa position initiale. Il n’y a pas besoin d’animation de sortie car l’animation est symétrique (l’opposé à le même résultat).

@include keyframes("animation_ico_download_arrow"){
	0%{   @include transform(rotateZ(0deg)); }
	25%{  @include transform(rotateZ(180deg)); }
	45%{  @include transform(rotateZ(360deg)); }
	60%{  @include transform(rotateZ(540deg)); }
	70%{  @include transform(rotateZ(565deg)); }
	75%{  @include transform(rotateZ(570deg)); }
	100%{ @include transform(rotateZ(540deg)); }
}

@include keyframes("animation_ico_download_arrow_reverse"){
	0%{   @include transform(rotateZ(540deg)); }
	25%{  @include transform(rotateZ(570deg)); }
	30%{  @include transform(rotateZ(565deg)); }
	40%{  @include transform(rotateZ(540deg)); }
	55%{  @include transform(rotateZ(360deg)); }
	75%{  @include transform(rotateZ(360deg)); }
	100%{ @include transform(rotateZ(360deg));}
}

@include keyframes("animation_ico_download_plinth"){
	0%{   @include transform(translateY(0%)); }
	10%{  @include transform(translateY(5%)); }
	90%{  @include transform(translateY(5%)); }
	100%{ @include transform(translateY(0%)); }
}

Bon le seul truc chiant c’est de gérer le mouseleave. En CSS il n’y a pas vraiment de solution miracle pour ce genre de truc, ou du moins, je ne la connais pas encore (si t’en as une, je suis preneur) donc un p’tit coup de jQuery fera l’affaire ! Ici je vais jouer avec l’ajout d’une classe sur le span. Enter ça veut dire que la souris est dessus et leave c’est quand la souris quitte l’élément.

$(".download span").mouseenter(function(){
	$(this).removeClass("leave").addClass("enter");
});

$(".download span").mouseleave(function(){
	$(this).removeClass("enter").addClass("leave");
});

Reste le plus important ! Balancer les animations en CSS. Pour l’entrée j’ai choisi un délai de 0,9 seconde et pour la sortie quelque chose d’un peu plus rapide pour avoir une impression de fluidité, soit 0,5 seconde. Le forwards à la fin est important, il permet à l’animation de ne pas revenir au début.

.download{
	span{
		&.leave{
			svg{
				path.first{
					@include animation(animation_ico_download_arrow_reverse 0.5s linear forwards);
				}
				path.second{
					@include animation(animation_ico_download_plinth 0.5s linear forwards);
				}
			}
		}
		&.enter{
			svg{	
				path.first{
					@include animation(animation_ico_download_arrow 0.9s linear forwards);
				}
				path.second{
					@include animation(animation_ico_download_plinth 0.9s linear forwards);	
				}
			}
		}				
	}
}

Résultat

Voici le résultat, mets ta souris sur l’icône !

Alternative

Cette animation CSS est bien pour deux raisons, la première c’est qu’elle est plutôt sexy et la seconde, c’est parce que je l’ai faite moi-même, donc forcément, je ne vais pas dire le contraire…

Cependant, lorsque que l’utilisateur survole l’icône et qu’il sort de la zone avant que l’animation ait fini de jouer, l’animation passe directement à la fin et joue l’animation de sortie, il y a comme une cassure. Vu le temps relativement rapide de l’animation, je pourrais dire que ce n’est pas grave et que c’est bien comme ça, mais il existe des solutions pour palier à ce genre de problème et c’est là que notre ami le JavaScript entre en jeu !

Le maître de l'animation

Pour m’aider dans la transposition de l’animation en JavaScript, je vais utiliser la bibliothèque GSAP, qui est une des meilleures bibliothèques d’animations de ce genre.

Je déclare deux TimelineLite, l’une pour l’animation de la flèche et l’autre pour le socle. J’utilise principalement la méthode to() qui permet d’animer un élément vers les propriétés renseignées. Ce qui est cool, c’est qu’on peut définir la durée de l’animation mais aussi à partir de quand la jouer (dans la pratique c’est vraiment simple d’utilisation).

J’ai changé légèrement la durée des animations, mais l’idée reste la même. J’ai utilisé un stop(), qui me permet de bloquer l’animation sinon elle est jouée directement au chargement de la page.
Ensuite, même concept au niveau du mouseenter et mouseleave, sauf qu’ici je n’attache pas de classe, je vais lancer l’animation d’entrée au survol, et pour la sortie je vais utiliser la méthode reverse() qui permet tout simplement de rebobiner l’animation. À la différence du CSS, il est beaucoup plus facile de coder l’attente de fin d’animation et le lancement de l’animation de sortie.

current_timeline_ico_download_arrow = new TimelineLite();
var download_svg_first = $(".download svg .first");
current_timeline_ico_download_arrow.to(download_svg_first, 0, {transformOrigin:'50% 50%'}, 0);
current_timeline_ico_download_arrow.to(download_svg_first, 0.7, {rotationZ:570}, 0.1);
current_timeline_ico_download_arrow.to(download_svg_first, 0.2, {rotationZ:540}, 0.9);
current_timeline_ico_download_arrow.to(download_svg_first, 0, {rotationZ:0}, 5);
current_timeline_ico_download_arrow.stop();
			
current_timeline_ico_download_plinth = new TimelineLite();	
var download_svg_second = $(".download svg .second");
current_timeline_ico_download_plinth.to(download_svg_second, 0.1, {y:6}, 0);	
current_timeline_ico_download_plinth.to(download_svg_second, 0.1, {y:0}, 1);	
current_timeline_ico_download_plinth.stop();			
			
$(".module .download a").mouseenter(function(){
	current_timeline_ico_download_arrow.play();
	current_timeline_ico_download_plinth.play();
});
$(".module .download a").mouseleave(function(){
	current_timeline_ico_download_arrow.reverse();
	current_timeline_ico_download_plinth.reverse();
});

Voilà que cet article prend fin ! Je suis très content du résultat et j’ai vraiment trouvé ça marrant. Je me rends compte que l’animation est un métier à part, il y a tellement de choses à devoir maîtriser et les possibilités sont quasiment infinies. Si tu connais des techniques d’animation ou des astuces n’hésite surtout pas à partager !

17/09/2016

Yann Vangampelaere - nouslesdevs -

Sinon jete un coup d’oeil aux autres catégories

Ma boîte aux lettres

Tu veux me demander quelque chose ?