Curseurs 3D CSS Infinite PlatoBlockchain Data Intelligence. Recherche verticale. Aï.

Curseurs 3D CSS infinis

Dans cette série, nous avons créé des curseurs d'image avec rien d'autre que du HTML et du CSS. L'idée est que nous pouvons utiliser le même balisage mais un CSS différent pour obtenir des résultats très différents, quel que soit le nombre d'images que nous lançons. Nous avons commencé avec un curseur circulaire qui tourne à l'infini, un peu comme un fidget spinner qui contient des images. Ensuite, nous en avons créé un qui feuillette une pile de photos.

Cette fois-ci, nous plongeons dans la troisième dimension. Cela va sembler difficile au début, mais une grande partie du code que nous examinons est exactement ce que nous avons utilisé dans les deux premiers articles de cette série, avec quelques modifications. Donc, si vous ne faites que commencer la série, je vous suggère de consulter les autres pour le contexte des concepts que nous utilisons ici.

Série de curseurs CSS

C'est ce que nous visons :

À première vue, on dirait que nous avons un cube rotatif avec quatre images. Mais en réalité, on a affaire à six images au total. Voici le curseur sous un angle différent :

Maintenant que nous avons un bon visuel de la façon dont les images sont disposées, disséquons le code pour voir comment nous y parvenons.

La configuration de base

Même code HTML que le reste des curseurs que nous avons utilisés pour les autres curseurs :

Et encore une fois, nous utilisons CSS Grid pour placer les images dans une pile, l'une au-dessus de l'autre :

.gallery {
  display: grid;
}
.gallery > img {
  grid-area: 1 / 1;
  width: 160px;
  aspect-ratio: 1;
  object-fit: cover;
}

L'animation

La logique de ce curseur est très similaire à le curseur circulaire du premier article. En fait, si vous regardez à nouveau la vidéo ci-dessus, vous pouvez voir que les images sont placées de manière à créer un polygone. Après une rotation complète, il revient à la première image.

Nous nous sommes appuyés sur le CSS transform-origin et les animation-delay propriétés pour ce premier curseur. La même animation est appliquée à tous les éléments de l'image, qui tournent autour du même point. Ensuite, en utilisant différents délais, nous plaçons correctement toutes les images autour d'un grand cercle.

L'implémentation sera un peu différente pour notre slider 3D. En utilisant transform-origin ne fonctionnera pas ici car nous travaillons en 3D, nous utiliserons donc transform au lieu de placer correctement toutes les images, puis faites pivoter le conteneur.

Nous recherchons à nouveau Sass pour pouvoir parcourir le nombre d'images et appliquer nos transformations :

@for $i from 1 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
     transform: 
       rotate(#{360*($i - 1) / $n}deg) /* 1 */
       translateY(50% / math.tan(180deg / $n)) /* 2 */ 
       rotateX(90deg); /* 3 */
  }
}

Vous vous demandez peut-être pourquoi nous sautons directement dans Sass. Nous avons commencé avec un nombre fixe d'images en utilisant le CSS vanilla dans les autres articles avant de généraliser le code avec Sass pour tenir compte de n'importe quel nombre (N) d'images. Eh bien, je pense que vous avez compris l'idée maintenant et que nous pouvons supprimer tout ce travail de découverte pour arriver à la véritable mise en œuvre.

Le transform propriété prend trois valeurs, que j'ai illustré ici:

Curseurs 3D CSS infinis

Nous faisons d'abord pivoter toutes les images les unes au-dessus des autres. L'angle de rotation dépend du nombre d'images. Pour N images, nous avons un incrément égal à 360deg/N. Ensuite nous translate toutes les images de la même quantité de manière à ce que leurs points centraux se rejoignent sur les côtés.

Montrant la pile d'images disposées à plat dans un cercle avec une ligne rouge passant par le point central des images.
Curseurs 3D CSS infinis

Il y a une géométrie ennuyeuse qui aide à expliquer comment tout cela fonctionne, mais la distance est égale à 50%/tan(180deg/N). Nous avons traité une équation similaire lors de la création du curseur circulaire ( transform-origin: 50% 50%/sin(180deg/N) ).

Enfin, nous faisons pivoter les images autour de l'axe des x en 90deg pour obtenir l'arrangement que nous voulons. Voici une vidéo qui illustre ce que fait la dernière rotation :

Maintenant, tout ce que nous avons à faire est de faire pivoter tout le conteneur pour créer notre curseur infini.

.gallery {
  transform-style: preserve-3d;
  --_t: perspective(280px) rotateX(-90deg);
  animation: r 12s cubic-bezier(.5, -0.2, .5, 1.2) infinite;
}
@keyframes r {
  0%, 3% {transform: var(--_t) rotate(0deg); }
  @for $i from 1 to $n {
    #{($i/$n)*100 - 2}%, 
    #{($i/$n)*100 + 3}% {
      transform: var(--_t) rotate(#{($i / $n) * -360}deg);
    }  
  }
  98%, 100% { transform: var(--_t) rotate(-360deg); }
}

Ce code peut être difficile à comprendre, alors revenons en arrière un instant et revoyons l'animation que nous avons faite pour le curseur circulaire. Voici ce que nous avons écrit dans ce premier article :

.gallery {
  animation: m 12s cubic-bezier(.5, -0.2, .5, 1.2) infinite;
}
@keyframes m {
  0%, 3% { transform: rotate(0); }
  @for $i from 1 to $n {
    #{($i / $n) * 100 - 2}%,
    #{($i / $n) * 100 + 3}% { 
      transform: rotate(#{($i / $n) * -360}deg);
    }  
  }
  98%, 100% { transform: rotate(-360deg); }
}

Les images clés sont presque identiques. Nous avons les mêmes valeurs de pourcentage, la même boucle et la même rotation.

Pourquoi les deux sont-ils identiques ? Parce que leur logique est la même. Dans les deux cas, les images sont disposées autour d'une forme circulaire et nous devons faire pivoter l'ensemble pour afficher chaque image. C'est ainsi que j'ai pu copier les images clés du curseur circulaire et utiliser ce même code pour notre curseur 3D. La seule différence est que nous devons faire pivoter le conteneur de -90deg le long de l'axe des x pour voir les images puisque nous les avons déjà tournées de 90deg sur le même axe. Ensuite, nous ajoutons une touche de perspective pour obtenir l'effet 3D.

C'est ça! Notre curseur est terminé. Voici à nouveau la démo complète. Tout ce que vous avez à faire est d'ajouter autant d'images que vous le souhaitez et de mettre à jour une variable pour le faire fonctionner.

Curseur 3D vertical

Puisque nous jouons dans l'espace 3D, pourquoi ne pas faire une version verticale du slider précédent ? Le dernier tourne le long de l'axe z, mais nous pouvons également nous déplacer le long de l'axe x si nous le voulons.

Si vous comparez le code des deux versions de ce curseur, vous ne remarquerez peut-être pas immédiatement la différence car il ne s'agit que d'un seul caractère ! j'ai remplacé rotate() comprenant rotateX() à l'intérieur des images clés et de l'image transform. C'est tout!

En tant que professionnels, rotate() équivaut à rotateZ(), donc en changeant l'axe de Z à X nous transformons le curseur de la version horizontale en version verticale.

Curseur de cube

On ne peut pas parler de 3D en CSS sans parler de cubes. Et oui, cela signifie que nous allons faire une autre version du slider.

L'idée derrière cette version du curseur est de créer une forme de cube réelle avec les images et de faire pivoter l'ensemble autour des différents axes. Comme c'est un cube, on a affaire à six faces. Nous allons utiliser six images, une pour chaque face du cube. Donc, pas de Sass mais retour au CSS vanille.

Cette animation est un peu écrasante, non? Par où commencer ?

Nous avons six visages, nous devons donc effectuer au moins six rotations pour que chaque image obtienne un tour. Eh bien, en fait, nous avons besoin de cinq rotations - la dernière nous ramène au premier visage de l'image. Si vous prenez un Rubik's Cube - ou un autre objet en forme de cube comme un dé - et que vous le faites tourner avec votre main, vous aurez une bonne idée de ce que nous faisons.

.gallery {
  --s: 250px; /* the size */

  transform-style: preserve-3d;
  --_p: perspective(calc(2.5*var(--s)));
  animation: r 9s infinite cubic-bezier(.5, -0.5, .5, 1.5);
}

@keyframes r {
  0%, 3%   { transform: var(--_p); }
  14%, 19% { transform: var(--_p) rotateX(90deg); }
  31%, 36% { transform: var(--_p) rotateX(90deg) rotateZ(90deg); }
  47%, 52% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg); }
  64%, 69% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg); }
  81%, 86% { transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg) rotateZ(90deg); }
  97%, 100%{ transform: var(--_p) rotateX(90deg) rotateZ(90deg) rotateY(-90deg) rotateX(90deg) rotateZ(90deg) rotateY(-90deg); }
}

Le transform La propriété commence par zéro rotation et, à chaque état, nous ajoutons une nouvelle rotation sur un axe spécifique jusqu'à atteindre six rotations. Ensuite, nous revenons à la première image.

N'oublions pas le placement de nos images. Chacun est appliqué à une face du cube en utilisant transform:

.gallery img {
  grid-area: 1 / 1;
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
  transform: var(--_t,) translateZ(calc(var(--s) / 2));
}
.gallery img:nth-child(2) { --_t: rotateX(-90deg); }
.gallery img:nth-child(3) { --_t: rotateY( 90deg) rotate(-90deg); }
.gallery img:nth-child(4) { --_t: rotateX(180deg) rotate( 90deg); }
.gallery img:nth-child(5) { --_t: rotateX( 90deg) rotate( 90deg); }
.gallery img:nth-child(6) { --_t: rotateY(-90deg); }

Vous pensez probablement qu'il y a une logique complexe étrange derrière les valeurs que j'utilise ici, n'est-ce pas ? Et bien non. Tout ce que j'ai fait a été d'ouvrir DevTools et de jouer avec différentes valeurs de rotation pour chaque image jusqu'à ce que je réussisse. Cela peut sembler stupide mais, bon, ça marche - d'autant plus que nous avons un nombre fixe d'images et que nous ne recherchons pas quelque chose qui prend en charge N images.

En fait, oubliez les valeurs que j'utilise et essayez de faire le placement par vous-même comme exercice. Commencez avec toutes les images empilées les unes sur les autres, ouvrez les DevTools et c'est parti ! Vous vous retrouverez probablement avec un code différent et c'est très bien. Il peut y avoir différentes manières de positionner les images.

Quel est le truc avec la virgule à l'intérieur du var()? Est-ce une faute de frappe ?

Ce n'est pas une faute de frappe alors ne l'enlevez pas ! Si vous le supprimez, vous remarquerez qu'il affecte le placement de la première image. Vous pouvez voir que dans mon code j'ai défini --_t pour toutes les images sauf la première car je n'ai besoin que d'une traduction pour celle-ci. Cette virgule fait retomber la variable sur une valeur nulle. Sans la virgule, nous n'aurons pas de repli et la valeur entière sera invalide.

Du la spécification:

Remarque : c'est-à-dire var(--a,) est une fonction valide, spécifiant que si le --a propriété personnalisée est invalide ou manquante, la var()` doit être remplacé par rien.

Curseur de cube aléatoire

Un peu de hasard peut être une belle amélioration pour ce type d'animation. Ainsi, plutôt que de faire tourner le cube dans un ordre séquentiel, nous pouvons lancer les dés pour ainsi dire et laisser le cube rouler comme bon lui semble.

Cool non ? Je ne sais pas pour vous, mais je préfère cette version ! C'est plus intéressant et les transitions sont satisfaisantes à regarder. Et devine quoi? Vous pouvez jouer avec les valeurs pour créer votre propre curseur de cube aléatoire !

La logique n'est pas du tout aléatoire - elle apparaît simplement comme ça. Vous définissez un transform sur chaque image clé qui permet de montrer un visage et… eh bien, c'est vraiment ça ! Vous pouvez choisir n'importe quelle commande que vous voulez.

@keyframes r {
  0%, 3%   { transform: var(--_p) rotate3d( 0, 0, 0,  0deg); }
  14%,19%  { transform: var(--_p) rotate3d(-1, 1, 0,180deg); }
  31%,36%  { transform: var(--_p) rotate3d( 0,-1, 0, 90deg); }
  47%,52%  { transform: var(--_p) rotate3d( 1, 0, 0, 90deg); }
  64%,69%  { transform: var(--_p) rotate3d( 1, 0, 0,-90deg); }
  81%,86%  { transform: var(--_p) rotate3d( 0, 1, 0, 90deg); }
  97%,100% { transform: var(--_p) rotate3d( 0, 0, 0,  0deg); }
}

J'utilise rotate3d() cette fois, mais je compte toujours sur DevTools pour trouver les valeurs qui me conviennent. N'essayez pas de trouver une relation entre les images clés car il n'y en a tout simplement pas. Je définis des transformations séparées, puis je regarde le résultat "aléatoire". Assurez-vous que la première image est respectivement la première et la dernière image et affichez une image différente sur chacune des autres images.

Vous n'êtes pas obligé d'utiliser un rotate3d() transformer comme je l'ai fait. Vous pouvez également enchaîner différentes rotations comme nous l'avons fait dans l'exemple précédent. Jouez et voyez ce que vous pouvez trouver! J'attendrai que vous partagiez votre version avec moi dans la section des commentaires!

Emballage en place

J'espère que cette petite série vous a plu. Nous avons construit des curseurs amusants (et amusants) tout en apprenant beaucoup sur toutes sortes de concepts CSS en cours de route - du placement de la grille et de l'ordre d'empilement, aux retards d'animation et aux transformations. Nous avons même pu jouer avec un soupçon de Sass pour parcourir un tableau d'éléments.

Et nous avons tout fait avec exactement le même code HTML pour chaque curseur que nous avons créé. À quel point cela est cool? CSS est puissant et capable d'accomplir tant de choses sans l'aide de JavaScript.

Horodatage:

Plus de Astuces CSS