CSS Infinite 3D Sliders PlatoBlockchain Data Intelligence. Lodret søgning. Ai.

CSS Infinite 3D Sliders

I denne serie, har vi lavet billedskydere med intet andet end HTML og CSS. Ideen er, at vi kan bruge den samme markup, men forskellig CSS til at få vildt forskellige resultater, uanset hvor mange billeder vi smider i. Vi startede med en cirkulær skyder, der roterer uendeligt, ligesom en fidget spinner, der holder billeder. Så lavede vi en, der bladrer gennem en stak billeder.

Denne gang dykker vi ind i den tredje dimension. Det kommer til at se hårdt ud i starten, men meget af koden, vi kigger på, er præcis, hvad vi brugte i de første to artikler i denne serie, med nogle ændringer. Så hvis du lige er ved at komme ind i serien, vil jeg foreslå, at du tjekker de andre ud for at få kontekst på de koncepter, vi bruger her.

CSS Sliders-serien

Dette er, hvad vi sigter efter:

Ved første øjekast ser det ud til, at vi har en roterende terning med fire billeder. Men i virkeligheden har vi at gøre med seks billeder i alt. Her er skyderen fra en anden vinkel:

Nu hvor vi har et godt billede af, hvordan billederne er arrangeret, lad os dissekere koden for at se, hvordan vi når dertil.

Den grundlæggende opsætning

Samme HTML som resten af ​​skyderne, vi har brugt til de andre skydere:

Og endnu en gang bruger vi CSS Grid til at placere billederne i en stak oven på hinanden:

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

Animationen

Logikken for denne skyder ligner meget den cirkulære skyder fra den første artikel. Faktisk, hvis du tjekker videoen ovenfor igen, kan du se, at billederne er placeret på en måde, der skaber en polygon. Efter en fuld rotation vender den tilbage til det første billede.

Vi stolede på CSS transform-origin , animation-delay egenskaber for den første skyder. Den samme animation anvendes på alle billedelementerne, som roterer omkring det samme punkt. Derefter, ved at bruge forskellige forsinkelser, placerer vi alle billederne korrekt omkring en stor cirkel.

Implementeringen vil være lidt anderledes for vores 3D-skyder. Ved brug af transform-origin vil ikke fungere her, fordi vi arbejder i 3D, så vi vil bruge transform i stedet for at placere alle billederne korrekt, drej derefter beholderen.

Vi rækker ud efter Sass igen, så vi kan gennemgå antallet af billeder og anvende vores transformationer:

@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 */
  }
}

Du undrer dig måske over, hvorfor vi hopper direkte ind i Sass. Vi startede med et fast antal billeder ved hjælp af vanilla CSS i de andre artikler, før vi generaliserede koden med Sass for at tage højde for et hvilket som helst tal (N) af billeder. Nå, jeg tror, ​​du forstår ideen nu, og vi kan skære alt det opdagelsesarbejde ud for at komme til den rigtige implementering.

transform egenskaben tager tre værdier, som jeg har illustreret her:

CSS Infinite 3D Sliders

Vi roterer først alle billederne over hinanden. Rotationsvinklen afhænger af antallet af billeder. Til N billeder, har vi en stigning svarende til 360deg/N. Så vi translate alle billederne i samme mængde på en måde, der får deres midtpunkter til at mødes på siderne.

Viser stakken af ​​billeder arrangeret fladt i en cirkel med en rød linje, der løber gennem billedernes midtpunkt.
CSS Infinite 3D Sliders

Der er noget kedelig geometri, der hjælper med at forklare, hvordan alt dette fungerer, men afstanden er lig med 50%/tan(180deg/N). Vi behandlede en lignende ligning, da vi lavede den cirkulære skyder ( transform-origin: 50% 50%/sin(180deg/N) ).

Til sidst roterer vi billederne rundt om x-aksen med 90deg at få den ordning, vi ønsker. Her er en video, der illustrerer, hvad den sidste rotation gør:

Nu skal vi bare dreje hele beholderen for at skabe vores uendelige skyder.

.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); }
}

Den kode kan være svær at forstå, så lad os faktisk gå et øjeblik tilbage og gense den animation, vi lavede til den cirkulære skyder. Dette er, hvad vi skrev i den første artikel:

.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); }
}

Keyframes er næsten identiske. Vi har de samme procentværdier, den samme sløjfe og den samme rotation.

Hvorfor er begge ens? Fordi deres logik er den samme. I begge tilfælde er billederne arrangeret omkring en cirkulær form, og vi skal rotere det hele for at vise hvert billede. Det var sådan, jeg var i stand til at kopiere keyframes fra den cirkulære skyder og bruge den samme kode til vores 3D-skyder. Den eneste forskel er, at vi skal dreje beholderen ved -90deg langs x-aksen for at se billederne, da vi allerede har roteret dem med 90deg på samme akse. Så tilføjer vi et strejf af perspective for at få 3D-effekten.

Det er det! Vores slider er færdig. Her er den fulde demo igen. Alt du skal gøre er at tilføje så mange billeder som du vil og opdatere en variabel for at få det i gang.

Lodret 3D-skyder

Da vi spiller i 3D-rummet, hvorfor så ikke lave en lodret version af den forrige skyder? Den sidste roterer langs z-aksen, men vi kan også bevæge os langs x-aksen, hvis vi vil.

Hvis du sammenligner koden for begge versioner af denne skyder, opdager du måske ikke umiddelbart forskellen, fordi det kun er ét tegn! jeg erstattede rotate() med rotateX() inde i keyframes og billedet transform. Det er det!

Det skal bemærkes, at rotate() svarer til rotateZ(), så ved at ændre aksen fra Z til X vi forvandler skyderen fra den vandrette version til den lodrette.

Kubeskyder

Vi kan ikke tale om 3D i CSS uden taler om terninger. Og ja, det betyder, at vi skal lave en anden version af skyderen.

Ideen bag denne version af skyderen er at skabe en egentlig kubeform med billederne og rotere hele tingen rundt om den anden akse. Da det er en terning, har vi at gøre med seks ansigter. Vi bruger seks billeder, et for hver side af terningen. Så ingen Sass men tilbage til vanilla CSS.

Den animation er lidt overvældende, ikke? Hvor starter du overhovedet?

Vi har seks ansigter, så vi skal udføre mindst seks rotationer, så hvert billede får en tur. Nå, faktisk har vi brug for fem rotationer - den sidste bringer os tilbage til det første billedansigt. Hvis du tager fat i en Rubik's Cube - eller en anden terningformet genstand som terninger - og roterer den med din hånd, har du en god idé om, hvad vi laver.

.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); }
}

transform egenskab starter med nul rotationer, og i hver tilstand tilføjer vi en ny rotation på en bestemt akse, indtil vi når seks rotationer. Så er vi tilbage til det første billede.

Lad os ikke glemme placeringen af ​​vores billeder. Hver enkelt påføres en flade af terningen ved hjælp af 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); }

Du tænker sikkert, at der er mærkelig kompleks logik bag de værdier, jeg bruger der, ikke? Altså nej. Alt jeg gjorde var at åbne DevTools og lege med forskellige rotationsværdier for hvert billede, indtil jeg fik det rigtigt. Det lyder måske dumt, men hey, det virker - især da vi har et fast antal billeder, og vi ikke leder efter noget, der understøtter N billeder.

Glem faktisk de værdier, jeg bruger, og prøv at udføre placeringen på egen hånd som en øvelse. Start med alle billederne stablet oven på hinanden, åbn DevTools, og gå! Du vil sandsynligvis ende med en anden kode, og det er helt fint. Der kan være forskellige måder at placere billederne på.

Hvad er tricket med kommaet inde i var()? Er det en tastefejl?

Det er ikke en tastefejl, så fjern det ikke! Hvis du fjerner det, vil du bemærke, at det påvirker placeringen af ​​det første billede. Det kan du se i min kode, jeg definerede --_t for alle billeder undtagen det første, fordi jeg kun mangler en oversættelse til det. Dette komma får variablen til at falde tilbage til en nulværdi. Uden kommaet vil vi ikke have en reserve, og hele værdien vil være ugyldig.

Fra specifikationen:

Bemærk: Dvs. var(--a,) er en gyldig funktion, der angiver, at hvis --a tilpasset egenskab er ugyldig eller mangler, den var()` bør erstattes med ingenting.

Tilfældig terningskyder

En lille smule tilfældighed kan være en god forbedring til denne form for animation. Så i stedet for at rotere terningen i sekventiel rækkefølge, kan vi kaste terningerne så at sige, og lade terningen rulle, som den vil.

Cool ikke? Jeg ved ikke med dig, men jeg kan bedre lide denne version! Det er mere interessant, og overgangene er tilfredsstillende at se. Og gæt hvad? Du kan lege med værdierne for at skabe din egen tilfældige terningskyder!

Logikken er faktisk slet ikke tilfældig - det ser bare sådan ud. Du definerer en transform på hver keyframe, der giver dig mulighed for at vise ét ansigt og... ja, det er virkelig det! Du kan vælge hvilken som helst ordre, du ønsker.

@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); }
}

jeg bruger rotate3d() denne gang, men jeg stoler stadig på, at DevTools finder de værdier, der føles "rigtige" for mig. Forsøg ikke at finde et forhold mellem keyframes, fordi der simpelthen ikke er en. Jeg definerer separate transformationer og ser derefter det "tilfældige" resultat. Sørg for, at det første billede er henholdsvis det første og det sidste billede, og vis et andet billede på hver af de andre rammer.

Du er ikke forpligtet til at bruge en rotate3d() transformere som jeg gjorde. Du kan også kæde forskellige rotationer, som vi gjorde i det foregående eksempel. Spil rundt og se, hvad du kan finde på! Jeg venter på, at du deler din version med mig i kommentarfeltet!

Indpakning op

Jeg håber du nød denne lille serie. Vi byggede nogle sjove (og sjove) skydere, mens vi lærte en masse om alle slags CSS-koncepter undervejs - fra gitterplacering og stablingsrækkefølge til animationsforsinkelser og transformationer. Vi kom endda til at lege med et strejf af Sass for at sløjfe gennem en række elementer.

Og vi gjorde det hele med nøjagtig den samme HTML for hver eneste skyder, vi lavede. Hvor fedt er det? CSS er meget kraftfuldt og i stand til at udrette så meget uden hjælp fra JavaScript.

Tidsstempel:

Mere fra CSS-tricks