La Cascade

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

Créer des sphères en CSS

par Donovan Hutchinson, 27 juillet 2014, css, html, animation, article original paru le 2 juillet 2014 dans Medium

Nous aussi nous pouvons faire des bulles, grâce à Donovan Hutchinson, maître des sphères.


J'ai parlé récemment de la création de triangles CSS qui utilisent les border-radius pour les angles. Essayons maintenant les sphères.

Flat design

Nous pouvons utiliser deux approches pour réaliser des sphères en CSS.

L'une d'elles consiste à créer une sphère en 3D, en utilisant de nombreux éléments. Il en existe de nombreux exemples remarquables. L'inconvénient est qu'elles requièrent du navigateur l'affichage de nombreux éléments, ce qui peut avoir un impact sur la performance. Par ailleurs, elles ont souvent un aspect un peu brut, du fait que l'affichage d'une sphère lisse et parfaite ferait appel à encore plus d'éléments.

Je vais donc tenter une autre approche, en utilisant les dégradés CSS pour créer un effet 3D sur un élément simple.

Démo et code source

Tous les exemples qui suivent sont accessibles via mon compte CodePen, ou en sélectionnant les liens “Edit on Codepen” de chaque exemple.

Dans les exemples de code, j'ai omis les préfixes constructeurs, mais je recommande l'utilisation d'un outil comme Autoprefixer, ou l'ajout manuel des préfixes.

Forme de base

Avant d'entrer dans les détails, nous allons créer un cercle, en commençant par le balisage HTML :

<figure class="circle"></figure>

Nous faisons appel à l'élément figure ici, mais on pourrait utiliser n'importe quel élément. figure est un élément utilisé en HTML pour représenter une image ou un diagramme faisant partie d'un contenu, mais dont la suppression n'aurait pas d'incidence sur la signification du contenu.

Pour créer un cercle à partir de cet élément, je vais lui donner une largeur et une hauteur, et un border-radius de 50%. Toute valeur supérieure à 50% aura pour résultat un coin parfaitement arrondi.

//CSS

.circle {
 display: block;
 background: black;
 border-radius: 50%;
 height: 300px;
 width: 300px;
 margin: 0;
}

Et voilà, un superbe disque :


Maintenant que nous avons notre cercle de base, nous pouvons commencer à lui ajouter quelques styles pour lui donner une allure sphérique.

Ombrages, notions de base

La première chose que les tutoriels de sphères en 3D vous montrent c'est l'ajout d'un dégradé radial simple, légèrement décalé vers le haut à gauche.

Nous pouvons le faire avec ce CSS :

.circle {
 display: block;
 background: black;
 border-radius: 50%;
 height: 300px;
 width: 300px;
 margin: 0;
 background: radial-gradient(circle at 100px 100px, #5cabff, #000);
}

Vous devriez obtenir ceci :

Dégradés radiaux

La propriété dégradé radial prend quelques arguments. Le premier est la position du point d'où partira le dégradé. La syntaxe est “forme at position”, soit dans notre exemple circle at 100px 100px, un cercle dont le point central est situé à 100px à partir de la gauche et 100px à partir du haut.

Ensuite, on spécifie une série de couleurs. Vous pouvez en spécifier plus de deux, mais dans ce cas il est nécessaire de préciser la position de chacune, afin que le dégradé sache où les couleurs se mélangent.

Dans notre exemple, nous n'utilisons que deux couleurs. Le navigateur supposera donc que la première est à 0% et la deuxième à 100%, et il réalisera un dégradé entre ces deux couleurs. Si nous voulions d'autres étapes dans le dégradé, nous pourrions spécifier les distances en pixels ou en pourcentages, comme nous le verrons tout à l'heure.

Bon, nous avons déjà quelque chose qui à une allure de 3D, ce n'est pas si mal mais essayons de faire mieux.

Ombres & 3D

Selon les ombres que vous appliquez à votre surface, vous pouvez donner un aspect différent à vos sphères. Mais pour commencer, plantons un décor pour installer la nôtre.

Le HTML s'enrichit un peu :

//HTML

<section class=”stage”>
 <figure class=”ball”><span class=”shadow”></span></figure>
</section>

L'élément “ball” contient un span que nous allons utiliser pour créer une ombre, et il est enveloppé dans une div “stage”. Celle-ci nous servira a créer la perspective et à positionner l'ombre, pour obtenir un effet 3D.

Appliquons maintenant quelques styles à stage et positionnons notre ombre :

//CSS

.stage {
 width: 300px;
 height: 300px;
 perspective: 1200px;
 perspective-origin: 50% 50%;
}

.ball .shadow {
 position: absolute;
 width: 100%;
 height: 100%;
 background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 50%);
 transform: rotateX(90deg) translateZ(-150px);
 z-index: -1;
}

Je n'ai pas intégré les préfixes dans cet exemple, mais ceux de CodePen sont entièrement préfixés. Je donne à la div stage une perspective de 1200px. La propriété perspective est similaire au point de fuite en 3D.

L'ombre est ensuite placée sous la balle, on lui donne un dégradé puis on la positionne en utilisant transform. Les transformations CSS nous permettent de faire tourner des objets, de les agrandir, de les déplacer ou de les étirer dans un espace en 3D. Nous faisons tourner l'ombre de 90° sur l'axe des x, puis nous la déplaçons de 150px vers le bas pour la mettre sous la balle. Comme nous avons établi une perspective, nous la regardons légèrement de haut en bas et nous voyons une forme ovale étirée.


C'est un peu mieux maintenant. Ajoutons encore quelques ombres à la balle elle-même.

Ombrages multiples

Dans le monde réel, il est rare qu'un objet soit illuminé d'un seul côté. Les surfaces renvoient la lumière vers d'autres surfaces et l'objet est éclairé de plusieurs côtés à la fois. Pour donner plus de réalisme à notre balle, nous allons faire comme s'il y avait deux sources de lumière, en utilisant un pseudo-élément pour ajouter deux dégradés.

.ball {
 display: inline-block;
 width: 100%;
 height: 100%;
 margin: 0;
 border-radius: 50%;
 position: relative;
 background: radial-gradient(circle at 50% 120%, #81e8f6, #76deef 10%, #055194 80%, #062745 100%);
}

.ball:before {
 content: “”;
 position: absolute;
 top: 1%;
 left: 5%;
 width: 90%;
 height: 90%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 0px, #ffffff, rgba(255, 255, 255, 0) 58%);
 filter: blur(5px);
 z-index: 2;
}

Ici nous avons deux dégradés un peu plus complexes.

Le premier est un effet subtil de réflexion de lumière par le bas, et nous l'appliquons à l'élément ball. Le centre du dégradé est positionné à mi-chemin de la largeur de la balle, et à 120% de sa hauteur. Le centre est donc situé hors de la surface de la balle. Cela évite que la couleur finale, qui est nette, ne soit visible et cela nous donne un dégradé plus doux.

Le second dégradé est le reflet d'un éclairage placé sur le dessus. Il est réglé à 90% de la largeur de la balle et à 90% de sa hauteur. Il est centré au sommet et se dégrade jusqu'à disparaître à peu près à mi-hauteur de la balle.

J'ai utilisé le pseudo-élément :before plutôt que de créer un nouvel élément pour contenir l'ombrage.

Comme ce dégradé est assez cru, j'ai utilisé le filtres CSS blur pour adoucir la lumière. Actuellement cet effet est disponible uniquement pour Chrome et Safari (webkit) mais il sera sans doute compatible avec d'autres navigateurs bientôt.

L'association de nos deux dégradés produit un effet bien plus intéressant :

Plus brillant

Notre effet est encore assez doux, nous allons lui ajouter un peu de brillant en créant quelque chose comme une boule de billard.

Pour réaliser cet effet, nous allons utiliser comme précédemment un reflet léger par en-dessous, mais nous allons ajuster la lumière du dessus, qui sera plus petite et plus précise. Nous allons devoir utiliser deux pseudo-éléments pour contenir la couleur de la boule, la lumière venue du dessous et le reflet.

.ball {
 display: inline-block;
 width: 100%;
 height: 100%;
 margin: 0;
 border-radius: 50%;
 position: relative;
 background: radial-gradient(circle at 50% 120%, #323232, #0a0a0a 80%, #000000 100%);
}

.ball:before {
 content: “”;
 position: absolute;
 background: radial-gradient(circle at 50% 120%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 70%);
 border-radius: 50%;
 bottom: 2.5%;
 left: 5%;
 opacity: 0.6;
 height: 100%;
 width: 90%;
 filter: blur(5px);
 z-index: 2;
}

.ball:after {
 content: “”;
 width: 100%;
 height: 100%;
 position: absolute;
 top: 5%;
 left: 10%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8) 14%, rgba(255, 255, 255, 0) 24%);
 transform: translateX(-80px) translateY(-90px) skewX(-20deg);
 filter: blur(10px);
}

Ici, nous avons appliqué la couleur initiale en subtil dégradé sur la boule elle-même (.ball).

Le pseudo-élément :before contient une lumière un peu plus claire, qui commence à la base de la boule et crée un effet de reflet venu de la surface sur laquelle elle repose.

La nouveauté ici est l'ajout du pseudo-élément :after. Il contient un dégradé radial qui part d'un blanc quasi opaque au centre et devient transparent à environ 24%. Cela crée un effet blanc brillant auquel, pour lui donner plus de réalisme, nous appliquons une transformation CSS.

La transformation consiste à déplacer le reflet vers la gauche de 80px et vers le haut de 90px et à étirer la forme. L'effet skew étire le cercle selon l'axe des x, pour qu'il ressemble à l'éclat qu'on verrait sur une boule.

Boule n°8

Et pendant que nous y sommes, ajoutons-lui le numéro 8.

Nous avons besoin d'un élément supplémentaire pour contenir le 8, et de quelques styles pour le placer sur la boule.

//HTML

<section class=”stage”>
 <figure class=”ball”>
 <span class=”shadow”></span>
 <span class=”eight”></span>
 </figure>
</section>

//CSS

.ball .eight {
 width: 110px;
 height: 110px;
 margin: 30%;
 background: white;
 border-radius: 50%;
 transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
 position: absolute;
}

.ball .eight:before {
 content: “8";
 display: block;
 position: absolute;
 text-align: center;
 height: 80px;
 width: 100px;
 left: 50px;
 margin-left: -40px;
 top: 44px;
 margin-top: -40px;
 color: black;
 font-family: Arial;
 font-size: 90px;
 line-height: 104px;
}

Nous utilisons à nouveau le border-radius de 50% pour créer un cercle, et ce cercle est ensuite positionné en haut à droite en utilisant la propriété transform. Plutôt que de mettre le chiffre 8 en contenu, j'utilise le pseudo-sélecteur pour ajouter le contenu via CSS, puis pour étirer le chiffre de la même manière que le cercle qui le contient.

Et voilà une boule n°8 éclatante.

Je t'ai à l'oeil

Un truc sympa avec les transformations CSS, c'est qu'on peut les animer. Grâce aux keyframes CSS, vous pouvez décrire une série de transformations formant une animation, et les appliquer à un élément. Pour le démontrer, je vais créer et animer un oeil.

Première étape, nous allons modifier les couleurs utilisées dans notre exemple précédent. Quelques petits ajustements et nous aurons notre oeil. Tout d'abord le HTML :

<section class=”stage”>
 <figure class=”ball”>
 <span class=”shadow”></span>
 <span class=”iris”></span>
 </figure>
</section>

Le CSS est similaire, pour l'essentiel, à notre boule de billard, à l'exception de l'iris et de la pupille.

.iris {
 width: 40%;
 height: 40%;
 margin: 30%;
 border-radius: 50%;
 background: radial-gradient(circle at 50% 50%, #208ab4 0%, #6fbfff 30%, #4381b2 100%);
 transform: translateX(68px) translateY(-60px) skewX(15deg) skewY(2deg);
 position: absolute;
 animation: move-eye-skew 5s ease-out infinite;
}

.iris:before {
 content: “”;
 display: block;
 position: absolute;
 width: 37.5%;
 height: 37.5%;
 border-radius: 50%;
 top: 31.25%;
 left: 31.25%;
 background: black;
}

.iris:after {
 content: “”;
 display: block;
 position: absolute;
 width: 31.25%;
 height: 31.25%;
 border-radius: 50%;
 top: 18.75%;
 left: 18.75%;
 background: rgba(255, 255, 255, 0.2);
}

Un dégradé bleu forme la partie colorée de l'iris, puis on crée la pupille et un reflet avec des pseudo-éléments. J'ai également ajouté la propriété animation à l'élément .iris. Pour attacher une animation à un élément, on utilise la syntaxe suivante :

animation: animation-name 5s ease-out infinite;

Dans cet exemple, on appliquerait une animation intitulée “animation-name”, qui aurait une durée de 5 secondes, tournerait en boucle indéfiniment, et aurait une valeur d'introduction/sortie (easing) de ease-out. Ease-out est le fait pour l'animation de ralentir lorsqu'elle arrive à la fin, ce qui crée un effet plus naturel. NdT : Pour plus d'infos sur les animations et sur l'utilisation du timing, vous pouvez consulter cet article d'alsacréations ou celui-ci de Vincent de Oliveira.

Tant que nous n'avons pas créé notre animation, notre oeil est bien statique.

voir Spheres tutorial: 5 Eyeball de Donovan hutchinson dans CodePen

Créons quelques keyframes pour décrire la façon dont notre globe oculaire devrait se mouvoir.

//CSS

@keyframes move-eye-skew {
 0% {
 transform: none;
 }
 20% {
 transform: translateX(-68px) translateY(30px) skewX(15deg) skewY(-10deg) scale(0.95);
 }
 25%, 44% {
 transform: none;
 }
 50%, 60% {
 transform: translateX(68px) translateY(-40px) skewX(5deg) skewY(2deg) scaleX(0.95);
 }
 66%, 100% {
 transform: none;
 }
}

Les keyframes peuvent paraître un peu compliquées au début. Elles consistent à décrire l'état d'un élément au cours d'une série d'étapes. Chaque étape est exprimée par un pourcentage. Dans notre exemple, l'iris commencera sans aucune transformation appliquée. On est à 0%. Puis, à 20% de la durée de l'animation (la nôtre fait 5 secondes, donc la première étape se situe à 1 seconde), une transformation est appliquée : l'objet est déplacé et étiré vers la gauche. Comme il s'agit d'une animation, et non d'une suite d'états fixes, le navigateur calcule ce qui se passe entre ces deux points (0% et 20%) et crée une transition en douceur.

voir Spheres tutorial: 5b Eyeball (animated) de Donovan hutchinson dans CodePen

Il en va de même avec chaque keyframes, et l'animation tout entière dure 5 secondes.

Bulles

L'association des ombrages et des animations peut produire des effets intéressants. C'est l'été, on fait des bulles?

Pour fabriquer des bulles, on fait comme précédemment mais avec plus de transparence pour la couleur principale et deux pseudo-éléments pour ajouter la brillance.

J'ai créé un CodePen pour que vous voyiez le CSS :

voir Spheres tutorial: 6 Bubble (animated) de Donovan hutchinson dans CodePen

L'animation utilise la valeur scale de transform pour faire se dandiner notre petite bulle.

@keyframes bubble-anim {
 0% {
 transform: scale(1);
 }
 20% {
 transform: scaleY(0.95) scaleX(1.05);
 }
 48% {
 transform: scaleY(1.1) scaleX(0.9);
 }
 68% {
 transform: scaleY(0.98) scaleX(1.02);
 }
 80% {
 transform: scaleY(1.02) scaleX(0.98);
 }
 97%, 100% {
 transform: scale(1);
 }
}

L'animation s'applique à la bulle tout entière et à ses pseudo-éléments.

Utiliser des images

Jusqu'à présent, nos sphères ont été créées sans recourir à des images. L'utilisation d'une image de background peut ajouter des détails, tout en permettant l'application des effets que nous avons vus grâce aux pseudo-éléments. Par exemple, nous pouvons prendre une balle de tennis flat et créer une illusion de profondeur avec des dégradés.

La texture flat :

La sphère après ombrages :

voir Spheres tutorial: 7 Tennis ball de Donovan hutchinson dans CodePen

Le tour du monde

On peut aussi appliquer une animation à la position des images de background. Nous pouvons ainsi créer une mappemonde.

image plate du monde

Cette image plate a été légèrement étirée en haut et en bas pour être utilisée comme image de background.

Avec un peu d'ombrages et d'animations, nous pouvons créer un globe qui a des allures de 3D.

voir Globe de Donovan hutchinson dans CodePen

NdT : Du même auteur, vous pouvez consulter Portal CSS sur La Cascade, une intro ludique aux transformations 3D et aux animations CSS.

Autres ressources externes

Articles de Donovan Hutchinson traduits dans La Cascade

Voir la page de Donovan Hutchinson et la liste de ses articles dans La Cascade.
Article original paru le 2 juillet 2014 dans Medium
Traduit avec l'aimable autorisation de Medium et de Donovan Hutchinson.
Copyright Medium © 2014