Catégories
Astuces et Design

CSS en 3D: apprendre à penser en cubes plutôt qu'en boîtes

Mon chemin pour apprendre le CSS était un peu peu orthodoxe. Je n’ai pas commencé en tant que développeur front-end. J'étais un développeur Java. En fait, mes premiers souvenirs de CSS étaient de choisir des couleurs pour les choses dans Visual Studio.

Ce n’est que plus tard que j’ai pu attaquer et trouver mon amour pour l’avant. Et l'exploration du CSS est venue plus tard. Quand il l'a fait, c'était à peu près au moment où CSS3 décollait. La 3D et l'animation étaient les enfants sympas du quartier. Ils ont presque façonné mon apprentissage du CSS. Ils m'ont attiré et en forme de (jeu de mots) ma compréhension du CSS plus que d'autres choses, comme la mise en page, la couleur, etc.

Ce que je veux dire, c'est que je fais tout le truc CSS 3D depuis une minute. Et comme pour tout ce avec quoi vous passez beaucoup de temps, vous finissez par affiner votre processus au fil des ans à mesure que vous perfectionnez cette compétence. Cet article décrit comment j'aborde actuellement le CSS 3D et présente quelques conseils et astuces qui pourraient vous aider!

<iframe title = "Tiroirs CSS purs utilisant

&

🔨🔩🤓 #CodePenChallenge "id =" cp_embed_mLaXRe "src =" https://codepen.io/jh3y/embed/preview/mLaXRe?height=300&slug-hash=mLaXRe&default-tabs=css,result&cod=htt .ps:// io "scrolling =" no "frameborder =" 0 "height =" 300 "allowtransparency =" true "class =" cp_embed_iframe "style =" width: 100%; débordement: masqué; ">

Tout est un cuboïde

Pour la plupart des choses, nous pouvons utiliser un cuboïde. Nous pouvons créer des formes plus complexes, bien sûr, mais elles prennent généralement un peu plus de considération. Les courbes sont particulièrement dures et il existe quelques astuces pour les gérer (mais plus à ce sujet plus tard).

Nous n'allons pas vous expliquer comment créer un cuboïde en CSS. Nous pouvons faire référence au post d'Ana Tudor pour cela, ou consulter ce screencast de moi en faisant un:

À la base, nous utilisons un élément pour envelopper notre cuboïde, puis transformer six éléments à l'intérieur. Chaque élément agit comme un côté de notre cuboïde. Il est important que nous appliquions transform-style: preserve-3d. Et ce n’est pas une mauvaise idée de l’appliquer partout. Il est probable que nous traiterons des cuboïdes imbriqués lorsque les choses deviennent plus complexes. Essayer de déboguer un manquant transform-style tout en sautant entre les navigateurs peut être douloureux.

* { transform-style: preserve-3d; }

Pour vos créations 3D qui sont plus que quelques visages, essayez d'imaginer toute la scène construite à partir de cuboïdes. Pour un exemple concret, considérons cette démo d'un livre 3D. C’est quatre cuboïdes. Un pour chaque couverture, un pour le dos et un pour les pages. L'utilisation de background-image fait le reste pour nous.

Mettre en scène

Nous allons utiliser des cuboïdes comme des pièces LEGO. Mais nous pouvons nous faciliter la vie en créant une scène et en créant un avion. Ce plan est l'endroit où notre création va s'asseoir et nous facilite la rotation et le déplacement de toute la création.

Pour moi, lorsque je crée une scène, j'aime d'abord la faire pivoter sur les axes X et Y. Puis je le pose à plat avec rotateX(90deg). De cette façon, lorsque je veux ajouter un nouveau cuboïde à la scène, je l'ajoute à l'intérieur de l'élément plan. Une autre chose que je vais faire ici est de définir position: absolute sur tous les cuboïdes.

.plane {
  transform: rotateX(calc(var(--rotate-x, -24) * 1deg)) rotateY(calc(var(--rotate-y, -24) * 1deg)) rotateX(90deg) translate3d(0, 0, 0);
}

Commencez avec un passe-partout

Créer des cuboïdes de différentes tailles et à travers un plan fait beaucoup de répétition pour chaque création. Pour cette raison, j'utilise Pug pour créer mes cuboïdes via un mixin. Si vous n’êtes pas familier avec Pug, j’ai écrit une introduction de 5 minutes.

Une scène typique ressemble à ceci:

//- Front
//- Back
//- Right
//- Left
//- Top
//- Bottom
mixin cuboid(className)
  .cuboid(class=className)
    - let s = 0
    while s < 6
      .cuboid__side
      - s++
.scene
  //- Plane that all the 3D stuff sits on
  .plane
    +cuboid('first-cuboid')

Quant au CSS. Ma classe cuboïde ressemble actuellement à ceci:

.cuboid {
  // Defaults
  --width: 15;
  --height: 10;
  --depth: 4;
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform-style: preserve-3d;
  position: absolute;
  font-size: 1rem;
  transform: translate3d(0, 0, 5vmin);
}
.cuboid > div:nth-of-type(1) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
}
.cuboid > div:nth-of-type(2) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(180deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(3) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(4) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(-90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(5) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(6) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * -1vmin)) rotateX(180deg);
  position: absolute;
  top: 50%;
  left: 50%;
}

Ce qui, par défaut, me donne quelque chose comme ça:

Propulsé par des variables CSS

Vous avez peut-être remarqué quelques variables CSS (alias propriétés personnalisées). C'est un gain de temps considérable. J'alimente mes cuboïdes avec des variables CSS.

  • --width: La largeur d'un cuboïde sur le plan
  • --height: La hauteur d'un cuboïde sur le plan
  • --depth: La profondeur d'un cuboïde dans le plan
  • --x: La position X sur le plan
  • --y: La position Y sur le plan

j'utilise vmin principalement comme mon unité de dimensionnement pour que tout reste réactif. Si je crée quelque chose à l'échelle, je pourrais créer une unité réactive. Nous avons évoqué cette technique dans un article précédent. Encore une fois, je pose l'avion à plat. Maintenant, je peux me référer à mes cuboïdes comme ayant une hauteur, une largeur et une profondeur. Cette démo montre comment déplacer un cuboïde autour du plan en modifiant ses dimensions.

Débogage avec dat.GUI

Vous avez peut-être remarqué ce petit panneau en haut à droite de certaines des démos que nous avons couvertes. C'est dat.GUI. C'est une bibliothèque de contrôleurs légère pour JavaScript, très utile pour le débogage de CSS 3D. Avec peu de code, nous pouvons mettre en place un panneau qui nous permet de changer les variables CSS au moment de l'exécution. Une chose que j'aime faire est d'utiliser le panneau pour faire pivoter le plan sur les axes X et Y. De cette façon, il est possible de voir comment les choses s'alignent ou fonctionnent sur une partie que vous ne voyez peut-être pas au début.


const {
  dat: { GUI },
} = window
const CONTROLLER = new GUI()
const CONFIG = {
  'cuboid-height': 10,
  'cuboid-width': 10,
  'cuboid-depth': 10,
  x: 5,
  y: 5,
  z: 5,
  'rotate-cuboid-x': 0,
  'rotate-cuboid-y': 0,
  'rotate-cuboid-z': 0,
}
const UPDATE = () => {
  Object.entries(CONFIG).forEach(((key, value)) => {
    document.documentElement.style.setProperty(`--${key}`, value)
  })
}
const CUBOID_FOLDER = CONTROLLER.addFolder('Cuboid')
CUBOID_FOLDER.add(CONFIG, 'cuboid-height', 1, 20, 0.1)
  .name('Height (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'cuboid-width', 1, 20, 0.1)
  .name('Width (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'cuboid-depth', 1, 20, 0.1)
  .name('Depth (vmin)')
  .onChange(UPDATE)
// You have a choice at this point. Use x||y on the plane
// Or, use standard transform with vmin.
CUBOID_FOLDER.add(CONFIG, 'x', 0, 40, 0.1)
  .name('X (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'y', 0, 40, 0.1)
  .name('Y (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'z', -25, 25, 0.1)
  .name('Z (vmin)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-x', 0, 360, 1)
  .name('Rotate X (deg)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-y', 0, 360, 1)
  .name('Rotate Y (deg)')
  .onChange(UPDATE)
CUBOID_FOLDER.add(CONFIG, 'rotate-cuboid-z', 0, 360, 1)
  .name('Rotate Z (deg)')
  .onChange(UPDATE)
UPDATE()

Si vous regardez la vidéo timelapse dans ce tweet. Vous remarquerez que je fais beaucoup pivoter l’avion au fur et à mesure que je construis la scène.

Ce code dat.GUI est un peu répétitif. Nous pouvons créer des fonctions qui prendront une configuration et généreront le contrôleur. Il faut un peu de bricolage pour répondre à vos besoins. J'ai commencé à jouer avec des contrôleurs générés dynamiquement dans cette démo.

Centrage

Vous avez peut-être remarqué que, par défaut, chaque parallélépipède est à moitié sous et à moitié au-dessus du plan. C’est intentionnel. C’est aussi quelque chose que j’ai commencé à faire récemment. Pourquoi? Parce que nous voulons utiliser l'élément contenant de nos cuboïdes comme centre du cuboïde. Cela facilite l'animation. Surtout si nous envisageons de tourner autour de l'axe Z. J'ai découvert cela lors de la création de «CSS is Cake». Après avoir fait le gâteau, j'ai alors décidé que je voulais que chaque tranche soit interactive. J'ai ensuite dû revenir en arrière et modifier mon implémentation pour fixer le centre de rotation de la tranche de retournement.

Ici, j'ai décomposé cette démo pour montrer les centres et comment le fait d'avoir un centre décalé affecterait la démo.

Positionnement

Si nous travaillons avec une scène plus complexe, nous pouvons la diviser en différentes sections. C'est là que le concept de sous-plans est utile. Considérez cette démo dans laquelle j'ai recréé mon espace de travail personnel.

Il se passe pas mal de choses ici et il est difficile de suivre tous les cuboïdes. Pour cela, nous pouvons introduire des sous-plans. Décomposons cette démo. La chaise a son propre sous-plan. Cela permet de le déplacer plus facilement dans la scène et de le faire pivoter - entre autres choses - sans rien affecter d'autre. En fait, on peut même faire tourner la toupie sans bouger les pieds!

Esthétique

Une fois que nous avons une structure, il est temps de travailler sur l'esthétique. Tout dépend de ce que vous faites. Mais vous pouvez obtenir des gains rapides en utilisant certaines techniques. J'ai tendance à commencer par rendre les choses «moche» puis à revenir en arrière et à créer des variables CSS pour toutes les couleurs et à les appliquer. Trois nuances pour une certaine chose nous permettent de différencier visuellement les côtés d'un cuboïde. Considérez cet exemple de grille-pain. Trois teintes recouvrent les côtés du grille-pain:

Notre mixin Pug de plus tôt nous permet de définir des noms de classe pour un cuboïde. L'application d'une couleur sur un côté ressemble généralement à ceci:

/* The front face uses a linear-gradient to apply the shimmer effect */
.toaster__body > div:nth-of-type(1) {
  background: linear-gradient(120deg, transparent 10%, var(--shine) 10% 20%, transparent 20% 25%, var(--shine) 25% 30%, transparent 30%), var(--shade-one);
}
.toaster__body > div:nth-of-type(2) {
  background: var(--shade-one);
}
.toaster__body > div:nth-of-type(3),
.toaster__body > div:nth-of-type(4) {
  background: var(--shade-three);
}
.toaster__body > div:nth-of-type(5),
.toaster__body > div:nth-of-type(6) {
  background: var(--shade-two);
}

Il est un peu difficile d’inclure des éléments supplémentaires avec notre mixin Pug. Mais n’oublions pas que chaque côté de notre cuboïde offre deux pseudo-éléments. Nous pouvons les utiliser pour divers détails. Par exemple, la fente pour grille-pain et la fente pour la poignée sur le côté sont des pseudo-éléments.

Une autre astuce consiste à utiliser background-image pour ajouter des détails. Par exemple, considérons l'espace de travail 3D. Nous pouvons utiliser des calques d'arrière-plan pour créer un ombrage. Nous pouvons utiliser des images réelles pour créer des surfaces texturées. Le sol et le tapis sont une répétition background-image. En fait, utiliser un pseudo-élément pour les textures est génial car nous pouvons les transformer si nécessaire, comme faire pivoter une image en mosaïque. J'ai également constaté que je scintillais dans certains cas en travaillant directement avec un côté cuboïde.

Un problème avec l'utilisation d'une image pour la texture est la façon dont nous créons différentes nuances. Nous avons besoin de nuances pour différencier les différents côtés. C’est là que le filter la propriété peut vous aider. Appliquer un brightness``() filtre sur les différents côtés d'un cuboïde peut les éclaircir ou les assombrir. Considérez cette table de retournement CSS. Toutes les surfaces utilisent une image de texture. Mais pour différencier les côtés, des filtres de luminosité sont appliqués.

<iframe title = "CSS pur

bascule! 😉🎉 #CodePenChallenge "id =" cp_embed_xJXvjP "src =" https://codepen.io/jh3y/embed/preview/xJXvjP?height=300&slug-hash=xJXvjP&default-tabs=css,result.costio=hepod. "scrolling =" no "frameborder =" 0 "height =" 300 "allowtransparency =" true "class =" cp_embed_iframe "style =" width: 100%; débordement: masqué; ">

Perspective de fumée et de miroirs

Qu'en est-il des formes - ou des caractéristiques que nous voulons créer qui semblent impossibles - en utilisant un ensemble fini d'éléments? Parfois, nous pouvons tromper l'œil avec un peu de fumée et des miroirs. Nous pouvons fournir un «faux» comme le sens de la 3D. La bibliothèque Zdog le fait bien et en est un bon exemple.

Considérez ce paquet de ballons. Les cordes qui les retiennent utilisent la bonne perspective et chacune a sa propre rotation, inclinaison, etc. Mais les ballons eux-mêmes sont plats. Si nous faisons pivoter le plan, les bulles maintiennent la rotation du contre-plan. Et cela donne cette «fausse» impression 3D. Essayez la démo et désactivez la compensation.

Parfois, il faut un peu de réflexion hors de la boîte. J'ai fait suggérer une plante d'intérieur pendant que je construisais l'espace de travail 3D. J'en ai quelques-uns dans la salle. Ma première pensée a été: "Non, je peux faire un pot carré, et comment pourrais-je faire toutes les feuilles?" En fait, nous pouvons également utiliser quelques astuces pour celui-ci. Prenez une image de certaines feuilles ou d'une plante. Supprimez l'arrière-plan avec un outil comme remove.bg. Positionnez ensuite plusieurs images au même endroit, mais faites-les pivoter chacune d'une certaine quantité. Maintenant, quand ils sont tournés, nous avons l’impression d’une plante en 3D.

S'attaquer aux formes inconfortables

Les formes gênantes sont difficiles à couvrir de manière générique. Chaque création a ses propres obstacles. Mais, il existe quelques exemples qui pourraient vous donner des idées pour aborder les choses. J'ai récemment lu un article sur l'UX des panneaux d'interface LEGO. En fait, aborder le travail CSS 3D comme s'il s'agissait d'un ensemble LEGO n'est pas une mauvaise idée. Mais le panneau d'interface LEGO est une forme que nous pourrions créer avec CSS (moins les crampons - je n'ai appris que récemment que c'est ce qu'ils s'appellent). C’est un cuboïde pour commencer. Ensuite, nous pouvons couper la face supérieure, rendre la face d'extrémité transparente et faire pivoter un pseudo-élément pour le joindre. Nous pouvons utiliser le pseudo-élément pour ajouter les détails avec certaines couches d'arrière-plan. Essayez d'activer et de désactiver le wireframe dans la démo ci-dessous. Si nous voulons les hauteurs et angles exacts pour les visages, nous pouvons utiliser des mathématiques pour entraîner l'hypoténeuse, etc.

Les courbes sont une autre chose difficile à couvrir. Les formes sphériques ne sont pas dans la timonerie CSS. Nous avons différentes options à ce stade. Une option consiste à accepter ce fait et à créer des polygones avec un nombre fini de côtés. Une autre consiste à créer des formes arrondies et à utiliser la méthode de rotation que nous avons mentionnée avec la plante. Chacune de ces options pourrait fonctionner. Mais encore une fois, c'est sur la base d'un cas d'utilisation. Chacun a des avantages et des inconvénients. Avec le polygone, nous abandonnons les courbes ou utilisons tellement d'éléments que nous obtenons une presque courbe. Ce dernier pourrait entraîner des problèmes de performances. Avec l'astuce de perspective, nous pouvons également nous retrouver avec des problèmes de performances en fonction. Nous abandonnons également la possibilité de styliser les «côtés» de la forme car il n'y en a pas.

Combat de Z

Dernier point, mais non des moindres, il vaut la peine de mentionner «combat en Z». C'est là que certains éléments d'un plan peuvent se chevaucher ou provoquer un scintillement indésirable. Il est difficile d’en donner de bons exemples. Il n’existe pas de solution générique pour cela. C’est quelque chose à aborder au cas par cas. La stratégie principale consiste à ordonner les choses dans le DOM comme il convient. Mais parfois, ce n’est pas le seul problème.

Être précis peut parfois causer des problèmes. Revenons à l'espace de travail 3D. Considérez la toile sur le mur. L'ombre est un pseudo-élément. Si nous plaçons la toile exactement contre le mur, nous allons rencontrer des problèmes. Si nous faisons cela, l'ombre et le mur vont se battre pour la position avant. Pour lutter contre cela, nous pouvons traduire légèrement les choses. Cela résoudra le problème et déclarera ce qui devrait être placé devant.

Essayez de redimensionner cette démonstration en activant et désactivant le «Décalage du canevas». Remarquez comment l'ombre scintille lorsqu'il n'y a pas de décalage? C’est parce que l’ombre et le mur se battent pour la vue. Le décalage définit le --x à une fraction de 1vmin que nous avons nommé --cm. C'est une unité réactive utilisée pour cette création.

C'est tout"!

Prenez votre CSS dans une autre dimension. Utilisez certains de mes conseils, créez les vôtres, partagez-les et partagez vos créations 3D! Oui, créer des éléments 3D en CSS peut être difficile et c'est certainement un processus que nous pouvons affiner au fur et à mesure. Différentes approches fonctionnent pour différentes personnes et la patience est un ingrédient indispensable. Je suis intéressé de voir où vous adoptez votre approche!

La chose la plus importante? Aie du plaisir avec ça!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *