Créer un loader de vidéo en HTML et CSS3! 1

J’ai quelques articles en cours de rédaction qui mettent décidément du temps à être terminés ! C’est que je suis un peu occupé en ce moment, mais comme j’ai expérimenté les animations en CSS3, je voulais rédiger un petit billet sur le sujet.

Ici on va voir comment utiliser les animations en CSS3, pour faire un loader de vidéo (animation d’attente de chargement d’une vidéo en streaming). Bien entendu je n’implémente pas la partie de chargement de la vidéo, et ce que je vais vous présenter et expliquer est une simple maquette (qui peut facilement être implémentée dans quelque chose de fonctionnel).

La partie HTML : Markup

Je ne répéterais jamais assez que votre structure HTML / de template doit être irréprochable. C’est cette essence même qui fait que l’on réussit sans contourner les problèmes par des solutions bricolées. Voilà pourquoi il est important de respecter certaines normes lorsqu’on écrit notre HTML.

Dans mon cas voici la structure que j’ai utilisée :

<h3>Simple pure CSS video loader </h3>
<div class="video_frame">
	<div class="video_overlay">
		<span class="loading_percentage"> 53% </span>
		<div class="outter_spinner">
			<div class="outter_circle">
				<div class="inner_circle">

				</div>
			</div>
		</div>
	</div>
</div>

On voit qu’il n y a rien de particulièrement complexe :

  • La div video_frame réprésente le cadre de la vidéo, contenant l’image de preview
  • La div video_overlay représente la filtre gris opaque qui recouvre l’image de preview de la vidéo
  • Le span loading_percentage contiendra le pourcentage de chargement. Ici c’est une valeur fixe.
  • La div outter_spinner contiendra le cercle exterieur qui va donner un effet de lumière en rotation autour du loader
  • La div outter_circle est le cercle principal.
  • La div inner_circle est le cercle intérieur, le coeur du cercle principal. C’est sur celui-ci qu’on va appliquer un effet de respiration.

Maintenant passons au CSS pour donner à tout cela l’apparence attendue.

Le CSS : passons à l’apparence

Nous allons commencer par situer les éléments dans la page. Le positionnement est une des premières choses à prendre en compte avec les éléments. Quand le positionnement est bon, on passe ensuite aux dimensions, puis les couleurs, effets, etc …

Un bon positionnement ne pourra jamais se faire sans une bonne base HTML. (je pense que je peux arrêter de répéter ca, vous avez saisi l’idée ;) )

Et il faut également respecter la hiérarchie des éléments : on va commencer par les plus gros morceaux : les éléments parents.

div.video_frame {
  margin: 50px auto;
  width: 640px;
  height: 360px;
  background: url("http://fortisfio.com/wp-content/uploads/2015/04/road.jpg") no-repeat;
  filter: sepia(10%);
  border-top: 10px #262626 solid;
  border-bottom: 10px #262626 solid;
}

Bon ici, comme je ne vais pas refaire petit morceau par petit morceau, je vous met le code CSS final de mon bloc video_frame. Rien de bien particulier, sauf peut-être le léger filtre sépia appliqué sur mon design, c’était pour lui donner un côté un peu vintage. Car en parlant de design, avant de continuer, sachez que les goûts et les couleurs; c’est subjectif ! Mon design est un peu particulier ici et ne s’intégrera pas bien dans n’importe qu’elle charte graphique. Je pense que ce que vous verrez en résultat final est plutôt dans la catégorie média/divertissement/jeux vidéo, ou sur des sites d’informations grunge/vintage. Ce n’est que mon avis, et après tout, il faut de tout pour faire le Web ;)

Bien après cette parenthèse, reprenons avec le design cette fois de l’overlay (ce nom est donnée communément aux couches de recouvrement opaque sur des éléments dans les pages Web).

div.video_overlay {
	position: relative;
	width:100%;
	height: 100%;
	background: rgba(40, 40, 40, 0.8);
}

Quelques explication s’imposent pour la suite : je défini la position relative à l’élément pour pouvoir positionner de façon absolue les éléments enfants, qui se baseront sur ce parent comme référence. Je défini aussi sa taille comme étant égale à celle de son élément parent, à savoir le conteneur de la vidéo. Enfin, son arrière-plan est généré par la fonction rgba() qui prend en paramètres les valeurs R(Red), G(Green), B(Blue) sur un octet en décimal (de 0 à 255) et en dernier la valeur alpha (la transparence appliquée, entre 0 et 1) sous forme décimale.

Maintenant que le décor de la maquette est en place, passons aux éléments du loader.

div.outter_spinner {
	position: absolute;
	left: 39%;
	top: 100px;
	margin: 0 auto;
	width: 150px;
	height: 150px;
	background-color: white;
	border-left: 1px white dotted;
	border-top: none;
	border-right: none;
	border-bottom: none;
	border-radius: 50%;
        box-shadow: 0px 2px 3px white;
}

La position absolute était ici nécéssaire pour ne pas avoir à intégrer du responsive design et que la maquette reste inchangée peut importe la taille de fenêtre. La petite spécificité à expliquer ici est le border-left d’1 pixel blanc qui va être la seule partie visible derrière le cercle principal. J’applique au border-left une ombre blanche, simulant une émission de lumière par le bord. L’effet ajouté sera, à la rotation, comme une batterie de led qui s’allume simultanément donnant un effet de contour lumineux rotatif. La démo sera forcément pour vous le meilleur moyen de comprendre ce que je tente avec difficulté d’expliquer ici :)

Le cercle principal sera quant à lui, stylisé de cette manière :

div.outter_circle {
	position: relative;
	padding: 0;
	margin: 0;
	width: 200px;
	height: 200px;
	border-radius: 50%;
	background: #cd3c1f;
	box-shadow: inset 0px 2px 3px #262626;
}

Même taille que son parent, ils vont se superposer. D’où l’effet du bord seul qui va ressortir. Je rajoute une zone ombrée interne, à l’inverse du bord blanc du cercle parent afin de donné une impression que la lueur projette une ombre dans la zone opposée.

Le CSS du cercle intérieur :

div.inner_circle {
	position: absolute;
	left: 25px;
	top: 25px;
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background: #ff4720;
}

Ici on va placer le cercle intérieur au centre du cercle principal, avec un rayon de 50 pixels de moins. C’est sur ce cercle que l’on va ensuite appliquer l’effet de respiration.

Pour fini on va placer le span contenant le pourcentage de progression au centre du cercle interne :

span.loading_percentage {
	z-index: 5;
	position: absolute;
	left: 45%;
	top: 140px;
	color: white;
	font-size : 40px;
	margin: 0 auto;
	text-shadow: #262626 0px 3px 3px;
}

Je lui affecte un z-index à 5 pour qu’il apparaisse devant tous mes autres composants. Le text-shadow, qui créé une ombre portée sur le texte, peut plaire ou non, mais il s’inscrit dans le style graphique que j’ai initié.

Les animations CSS3 : action !

Je vais utilise les directives d’animation @keyframes pour mettre en mouvement le loader. Dans un premier temps, occupons nous du cercle extérieur (l’effet de lumière rotatif) :

@keyframes spinOutterCircle {
	 0% {
		 transform: rotateZ(0deg);
	 }

	 100% {
		 transform: rotateZ(360deg);
	 }
}

Tout simplement ! spinOutterCircle est le nom de mon animation, puis les directives 0% et 100% définissent l’état de l’élément au moment ou l’animation est à 0% (au début) et à 100% (complétée). Vous allez comprendre lorsque je vais ajouter dans le bloc CSS, la portion de code pour lier cette animation avec mon cercle :

div.outter_spinner {
	position: absolute;
	left: 39%;
	top: 100px;
	margin: 0 auto;
	width: 150px;
	height: 150px;
	background-color: white;
	border-left: 1px white dotted;
	border-top: none;
	border-right: none;
	border-bottom: none;
	border-radius: 50%;
        box-shadow: 0px 2px 3px white;
        animation: 3s spinOutterCircle infinite linear;
        -webkit-animation: 3s spinOutterCircle infinite linear;
	-o-animation: 3s spinOutterCircle infinite linear;
}

Les trois dernières lignes font référence aux différentes références à mon keyframe en fonction des kits des navigateurs. animation est utilisé par Internet Explorer et Firefox. -wekit-animation est utilisé par Chrome, tandis que -o-animation, comme vous l’aurez deviné est la syntaxe reconnue par Opéra.

Dans les paramètres présents, 3s fait référence au temps complet que l’animation met pour se terminer, spinOutterCircle appelle le keyframe de ce nom, le mot clé infinite fait en sorte de jouer l’animation en boucle et linear lui donne un effet de transition linéaire entre sa fin et son commencement. C’est à dire, quand elle est jouée en boucle avec une animation de type linéaire, on ne voit pas ou est le moment ou elle s’arrête ! (elle se rejoue dans la continuité).

Pour que Chrome comprenne la syntaxe du keyframe, il faut également rajouter celle-ci avec le mot clé -webkit, comme ceci :

@-webkit-keyframes spinOutterCircle {
	0% {
		transform: rotateZ(0deg);
	}

	100% {
		transform: rotateZ(360deg);
	}
}

Enfin, il ne reste plus qu’a intégrer mon animation de « respiration » au cercle intérieur. Je vais commencer par les deux directives keyframes :

@keyframes breathInnerCircle {
	 0% {
		 transform: scale(1,1);
	 }

	 100% {
		 transform: scale(1.2,1.2);
	 }
 }

@-webkit-keyframes breathInnerCircle {
	0% {
		transform: scale(1,1);
	}

	100% {
		transform: scale(1.2,1.2);
	}
}

Ici on veut appliquer une homothétie (un changement d’échelle) sur tout les axes de mon cercle. L’échelle du cercle passe donc de 1 à 1.2 sur x et y au cours de l’animation. On ne va passer les mêmes paramètres qu’a la première animation. Voyez plutôt :

div.inner_circle {
	position: absolute;
	left: 25px;
	top: 25px;
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background: #ff4720;
	animation: breathInnerCircle 1s 1.5s ease infinite alternate;
	-webkit-animation: breathInnerCircle 1s 1.5s ease infinite alternate;
	-o-animation: breathInnerCircle 1s 1.5s ease infinite alternate;
}

Pour la petite explication des 3 dernières lignes que j’ai ajoutées par rapport au bloc initial :

breathInnerCircle fait référence à ma deuxième keyframe, 1s fait référence au temps pour arriver à 100% de l’animation, 1.5s fait référence au temps pour revenir à l’état d’origine, ease est une transition permettant, de produire un autre effet que linear que j’ai expliqué avant. En effet, ease permet de produire un effet « smoothy« , qui va appliquer un léger ralentissement avant la fin de l’animation, et avant son commencement, pour simuler une inertie sur le mouvement (cela dit en passant c’est un effet parfait pour imiter une respiration). Et enfin, vous connaissez infinite qui va jouer l’animation en boucle, et alternate va définir de jouer l’animation en alternance de façon normale, puis de façon inversée, et ainsi de suite.

De cette façon, plutôt que d’avoir la croissance du cercle, et une décroissance brutale à sa taille d’origine à la fin de l’animation; celle-ci va repartir dans l’autre sens, et donc  faire décroitre le cercle de façon animée, jusqu’à atteindre sa taille originale. Voici enfin la lien de ce que tout cela donne, car vos yeux vous expliqueront, encore une fois, mieux que mes descriptions :

 Demo

La DEMO est disponible sur CSSDeck.

 Conclusion

Le CSS offre maintenant tellement de possibilité que l’on peut construire un design beaucoup plus évolué et travaillé qu’avant, et sans javascript ! Attention toutefois, il ne faut pas tomber dans le piège d’une utilisation systématique du CSS pour gérer les interfaces, car Javascript et ses multiples framework offrent des possibilités optimisées et puissantes également. Mais pour des petits composants graphiques sur les sites Web, qui ne sont pas forcément amenés à être modifiés (comme des loaders, des effets de formulaires, de menu, de survol d’images, …) c’est un excellent choix ! Le seul vrai problème reste encore les pavés de code en double, voire en triple pour répondre aux besoins des plusieurs navigateurs activement utilisés.

One comment on “Créer un loader de vidéo en HTML et CSS3!

  1. Répondre Web lyon nov 6, 2015 3 h 12 min

    En passant, j’aime beaucoup la charte graphique du site.

Laisser un commentaire