Salut, Les transformations 3D

Aujourd’hui suite et fin de la série sur les propriétés CSS avancées avec les transformations 3D. Cette fonction va utiliser plusieurs des transformations que nous avons découvertes en 2D, sauf que sur notre axe X / Y, nous allons ajouter une dimension, Z. Cela à l’air simple à dire, mais il y a quelques trucs qui sont un peu compliqués, tu verras à la fin de l’article, pourquoi j’ai mis autant de temps à l’écrire celui ci… chaud!

C’est grâce à cette dimension qu’il va être possible de donner de la profondeur et de la perspective à nos objets et notre page.

Alors n’allons pas trop vite en besogne, il n’est pas question pour le moment d’imaginer qu’on va apprendre à coder des programmes de réalité augmenté, ni des effets 3D que nous verrions avec des lunettes comme au cinéma. On en est pas encore là, en tout cas moi je n ‘en suis pas encore là…

Créer la perspective

La propriété perspective

J’ai commencé à parler de ce point dans l’introduction, la perspective va donc nous permettre de donner une impression de proximité ou d’éloignement par rapport à ce que l’on regarde. Cette propriété CSS simple à retenir, perspective, va nous permettre de définir la profondeur du champ de la scène que nous voulons construire. On exprimera la perspective en px ou en em.

Attention:

Plus la valeur de la perspective est petite, plus l’objet sera déformé. Quand on parle de perspective il y a forcément une notion d’angle quelque part, donc plus l’angle est grand, plus l’objet est proche et sera déformé. En revanche, si on recule la ligne d’horizon, l’angle va diminuer et les proportions de l’objet seront moins déformées. Cela dépend du rendu que tu recherches. J’espère être clair avec ces précisions?

N’hésites pas à faire le test pour voir l’impact de la valeur de la perspective. Essaye par exemple avec 200px et 1000px, pour cela, tu peux directement allez voir le résultat sur Codepen.

Cette propriété perspective: _____; est utilisée sur un élément parent lorsqu’on veut utiliser une transformation 3D sur un ensemble d’élément. Lorsqu’on veut réaliser une animation 3D sur un seul élément, on peut utiliser la propriété transform: perspective(__);.

transform: perspective(200px);
body{
 perspective:200px;
}

.element{
		transform:perspective(200px);
}

La première approche est loin d’être transcendante, voire même un peu décevante dans le rendu… J’ai tout de même fait un petit exemple dans Codepen. J’ai créé 2 div de même dimension, et lorsqu’on survole la grise, elle vient se mettre à coté de la violette. Grâce à l’effet de perspective, le carré bleu est devenu plus petit que le rouge, alors que l’on n’a pas changé la taille. Pour voir le résultat, tu peux aller voir sur Codepen. Pour mettre en évidence cette propriété, j’ai utilisé la propriété translate3d, que l’on verra plus loin.

Le point de fuite

Repense à tes cours d’Art Plastique au collège quand on te faisait dessiner des choses en perspective, le prof demandait de dessiner la ligne d’horizon, et toutes les parallèles  se rejoignaient sur un point de fuite. Quand tu es sur une grande ligne droite en voiture, si tu regardes au loin, les deux bords de la route se rejoignent sur un point: le point de fuite.

En CSS, il est possible de définir la position du point de fuite grâce à la propriété perspective-origin:  X(px) Y(px).

Cette propriété peut contenir 2 valeurs:

  • une valeur suivant X qui permet de  décaler le point d’origine sur l’axe des X (horizontale de gauche à droite),
  • une valeur suivant Y, permettant de décaler le point d’origine  sur l’axe Y (verticale de haut en bas).

Possibilité d’utiliser des valeurs négatives et ces valeurs peuvent être utilisées en px ou en em. Autre possibilité pour les valeurs de perspective-origin, tu peux utiliser les termes anglais suivant:

  • top (haut),
  • left (gauche),
  • right (droite),
  • bottom (bas),
  • center(au milieu, au centre).

Remarque:

Si tu ne déclares pas de perspective, aucune des animations que tu coderas ensuite ne prendra en compte la troisième dimension, suivant l’axe Z. Je me suis rendu compte de cela en bricolant ces propriétés, qui ne sont pas simple à prendre en main. J’ai encore beaucoup de temps à passer pour tout bien comprendre. Voyons donc maintenant ces propriétés…

La translation 3D

Nous avions vu rapidement dans un article précédent, comment faire des translations en 2D (Les transitions en CSS). Il était alors possible de déplacer un élément sur deux axes, X et Y.

Avec la 3D, nous allons ajouter un axe, Z, qui permets de donner un peu plus de profondeur à l’image que nous allons avoir à l’écran.

Cette translation va donner une impression d’éloignement ou de rapprochement de l’élément sélectionné. Dans Codepen, j’ai pris des images pour bien voir ce qu’il se passe. J’avais au départ fait les mêmes exemples avec des blocs colorés, mais c’était un peu pourrit et ça ne mettait pas assez bien les effets en évidence.

Comme tu le verras sur le projet Codepen lié à cet article, la translation 3d donne l’impression d’avoir réalisé une translation 2D plus un changement d’échelle avec scale (___), mais c’est bien de la 3D. Voilà comment coder cette propriété:

.div{
	transform: translate3d(50px, 10px, 20px);/* entre parenthèse, valeurs suivant X, Y et Z toujours dans cet ordre!!*/
}

Attention

Je ne suis pas tout à fait d’accord avec le repère proposé dans le cours d’Openclassrooms, car il me semble que sur l’axe des Y, les valeurs positives suivent un axe Y qui pointe vers le bas de la page et non vers le haut comme indiqué. Pour l’axe X et Z je suis d’accord avec ce qui est proposé. Pour vérifier cela, fait le test…

Dans l’article précédent, je t’avais parlé des matrices pour réaliser des combinaisons de transition, mais pour la 3D, je ne vais pas rentrer dans le détail. Il n’ai déjà pas simple d’utiliser ces propriétés quand on débute alors ajouter une dose de matrice au milieu de tout ça… J’ai plus l’impression que je vais y perdre du temps qu’autre chose, donc désolé si je n’en parle pas, pour le moment, je pense que j’ai juste besoin de savoir que ça existe, et j’ai plus d’aspirine…

Modifier l’échelle en 3D

Comme pour la translation, on va « simplement » ajouter une dimension, donc une composante Z dans notre série de facteur d’échelle, sauf que je ne vois pas différence?! Les translations suivant X et Y fonctionnent normalement, mais quand on ajoute le facteur suivant Z, rien ne change…

J’ai essayé de modifier la perspective et le point d’origine, mais rien ne change, si tu as une astuce ça m’intéresse!

Sinon voilà comment ça se code:

div{
	transform: scale3d(1,1,2); /* L'élément est sensé s'agrandir suivant un facteur 2 sur l'axe Z...*/
}

Je ne passe pas plus de temps sur ce sujet, c’est pas le plus transcendant…

La rotation 3D

Là ça commence à devenir un peu compliqué, puisque il va falloir donner les coordonnées de l’axe de rotation dans l’espace. Il va donc falloir que tu saisisses les valeurs X, Y et Z pour définir l’axe de rotation autour duquel ton élément va tourner. J’ai toujours pas d’aspirine…

La propriété rotate3d() contient 4 valeurs, (x, y, z, a):

  • x: nombre définissant la coordonnée,  suivant l’axe X, de l’axe de rotation,
  • y: nombre définissant la coordonnée,  suivant l’axe Y, de l’axe de rotation,
  • z: nombre définissant la coordonnée,  suivant l’axe Z, de l’axe de rotation
  • a: l’angle de rotation. Cette rotation est réalisée autour de l’axe précédemment définit par les coordonnée x, y, z.

Remarque importante:

Les composantes X, Y et Z ne comporte aucune unité, il s’agit simplement d’une coordonnée sur un axe. Il ne faut pas mettre d’unité comme px ou em. Si tu en mets, c’est très simple ça ne fonctionnera pas. J’ai fait cette erreur…

Voilà ce qu’il faut faire ci-dessous:

div{

	transform:rotate3d(50, 20,30, 20deg);
}

Lorsque l’angle est positif, la rotation est réalisée dans le sens des aiguilles d’une montre, dans le cas contraire, je te laisse imaginer ce que ça donne…

Pour un complément d’information je te conseille de lire la documentation du MDN, qui explique bien le concept, et si tu es à l’aise en math, il y a même des formules…

J’ai essayé de faire un exemple qui peut être exploitable dans tes projets, qui utilise notamment la rotation 3D. Au survol de l’image, elle se retourne à 180 degrès et laisse apparaître un texte écrit au dos. C’est un peu comme si tu retournais une carte postale pour lire ce qu’il y a au dos. Bon cet exemple est perfectible:

  • si par hasard j’ajoute un lien dans le texte je ne peux pas le cliquer dessus car dès que je bouge la souris, l’image réapparaît: genre de truc qui peu rapidement agacer un utilisateur. Je le sais, j’avais essayé de mettre un lien et ça m’a gonflé!
  • lorsqu’on ne survole plus le texte, cette image réapparaît brusquement, alors que j’aurais voulu qu’elle fasse gentiment le chemin inverse. J’ai cherché, mais je n’ai pas trouvé de possibilité de le faire juste en CSS. Si tu trouves une astuce, ça m’intéresse.

J’imagine que pour réaliser  cela, il va falloir ajouter une petite couche de Javascript… bientôt…

Il y a une astuce que j’ai découverte dans l’exemple de code du cours, après 3h de prise de tête et de recherche de solution (je n’ai pas voulu regarder la solution tout de suite). Il faut que l’image que tu souhaites afficher en arrière soit retourné par défaut à 180 degrés.

D’autre part, j’ai réalisé cet exemple avec les @keyframes mais je pense qu’il est possible de faire la même chose en utilisant juste les propriétés d’animation vues dans l’article précédent (Les animations CSS).

Bilan des effets CSS avancés

C’est donc la fin de cette série sur les effets CSS avancés, j’ai vraiment appris plein de choses, mais il faut encore que je manipule ces propriétés dans des projets concrets pour mieux les maîtriser.

Si comme moi tu suis le cours d’Openclassrooms, fais attention car je crois qu’il y a certaines choses incomplètes, erronées ou plus à jour, même si j’ai suivi la trame dans mon apprentissage et dans les articles qui en ont découlé. J’ai essayé de documenter un maximum mes articles et  j’espère vraiment que ça te permettra d’éviter de perdre du temps dans ton apprentissage, comme j’ai pu le faire… Mais c’est pas très grave, la recherche d’informations  n’est jamais une perte de temps, on apprend toujours un truc!

Pour la suite, je vais me lancer dans l’apprentissage de Javascript, cette fois c’est parti, depuis le temps que j’en parle!!

Je ne sais pas encore quelle forme prendront les articles pour ce sujet, je verrais en fonction des difficultés que je rencontre.

Je te dis à vendredi pour un prochain article,

A bientôt,

Guillaume