CSS Oneindige schuifregelaar die door polaroidafbeeldingen bladert PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

CSS Oneindige schuifregelaar die door polaroidafbeeldingen bladert

In het laatste artikel, hebben we een coole kleine schuif gemaakt (of "carrousel" als je daar de voorkeur aan geeft) die in een cirkelvormige richting draait. Deze keer gaan we er een maken die door een stapel polaroidafbeeldingen bladert.

Cool toch? Kijk nog niet helemaal naar de code, want er valt veel te ontrafelen. Doe mee, wil je?

CSS Sliders-serie

De basisopstelling

De meeste HTML en CSS voor deze schuifregelaar is vergelijkbaar met de ronde die we de vorige keer hebben gemaakt. In feite gebruiken we exact dezelfde opmaak:

En dit is de basis-CSS die onze ouder instelt .gallery container als een raster waarin alle afbeeldingen op elkaar zijn gestapeld:

.gallery  {
  display: grid;
  width: 220px; /* controls the size */
}
.gallery > img {
  grid-area: 1 / 1;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border: 10px solid #f2f2f2;
  box-shadow: 0 0 4px #0007;
}

Niets ingewikkelds tot nu toe. Zelfs voor de Polaroid-achtige stijl voor de afbeeldingen, gebruik ik alleen wat border en box-shadow. Je kunt het misschien beter doen, dus speel gerust met die decoratieve stijlen! We gaan de meeste aandacht besteden aan de animatie, wat het lastigste deel is.

Wat is de truc?

De logica van deze schuifregelaar is afhankelijk van de stapelvolgorde van de afbeeldingen - dus ja, we gaan ermee spelen z-index. Alle afbeeldingen beginnen met hetzelfde z-index waarde (2) die logischerwijs de laatste afbeelding bovenop de stapel zal maken.

We nemen die laatste afbeelding en schuiven deze naar rechts totdat de volgende afbeelding in de stapel wordt onthuld. Dan verkleinen we de afbeelding z-index waarde dan schuiven we het terug in het kaartspel. En sinds zijn z-index waarde lager is dan de rest van de afbeeldingen, wordt het de laatste afbeelding in de stapel.

Hier is een uitgeklede demo die de truc laat zien. Beweeg de afbeelding om de animatie te activeren:

Stel je nu voor dat dezelfde truc op alle afbeeldingen wordt toegepast. Hier is het patroon als we de gebruiken :nth-child() pseudo-selector om de afbeeldingen te onderscheiden:

  • We schuiven de laatste afbeelding (N). De volgende afbeelding is zichtbaar (N - 1).
  • We schuiven de volgende afbeelding (N - 1). De volgende afbeelding is zichtbaar (N - 2)
  • We schuiven de volgende afbeelding (N - 2). De volgende afbeelding is zichtbaar (N - 3)
  • (We gaan door met hetzelfde proces totdat we de eerste afbeelding bereiken)
  • We schuiven de eerste afbeelding (1). De laatste afbeelding (N) is weer zichtbaar.

Dat is onze oneindige slider!

De animatie ontleden

Als je je het vorige artikel herinnert, definieerde ik slechts één animatie en speelde ik met vertragingen om elke afbeelding te besturen. Hier gaan we hetzelfde doen. Laten we eerst proberen de tijdlijn van onze animatie te visualiseren. We beginnen met drie afbeeldingen en generaliseren het later voor elk willekeurig getal (N) van afbeeldingen.

CSS Oneindige schuifregelaar die door polaroidafbeeldingen bladert

Onze animatie is verdeeld in drie delen: "naar rechts schuiven", "naar links schuiven" en "niet bewegen". We kunnen gemakkelijk de vertraging tussen elke afbeelding identificeren. Als we bedenken dat de eerste afbeelding begint bij 0sen de duur is gelijk aan 6s, dan begint de tweede om -2s en de derde op -4s.

.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */

We kunnen ook zien dat het gedeelte "niet bewegen" tweederde van de hele animatie in beslag neemt (2*100%/3) terwijl de delen "naar rechts schuiven" en "naar links schuiven" samen een derde deel uitmaken - dus elk is gelijk aan 100%/6 van de totale animatie.

We kunnen onze animatie-keyframes als volgt schrijven:

@keyframes slide {
  0%     { transform: translateX(0%); }
  16.67% { transform: translateX(120%); }
  33.34% { transform: translateX(0%); }
  100%   { transform: translateX(0%); } 
}

ZIJN 120% is een willekeurige waarde. Ik had iets groters nodig dan 100%. De afbeeldingen moeten naar rechts schuiven, weg van de rest van de afbeeldingen. Om dat te doen, moet het op zijn minst bewegen 100% van zijn grootte. Daarom ging ik 120% - om wat extra ruimte te winnen.

Nu moeten we nadenken over de z-index. Vergeet niet dat we de afbeeldingen moeten bijwerken z-index waarde na het schuift naar rechts van de stapel, en vaardigheden we schuiven het terug naar de onderkant van de stapel.

@keyframes slide {
  0%     { transform: translateX(0%);   z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  100%   { transform: translateX(0% );  z-index: 1; }  
}

In plaats van één staat te definiëren bij de 16.67% (100%/6) punt in de tijdlijn definiëren we twee toestanden op bijna identieke punten (16.66% en 16.67%) waar de z-index waarde afneemt voordat we de afbeelding terugschuiven naar het kaartspel.

Dit is wat er gebeurt als we dat allemaal bij elkaar brengen:

Hmmm, het glijdende gedeelte lijkt goed te werken, maar de stapelvolgorde is helemaal vervormd! De animatie begint mooi omdat de bovenste afbeelding naar achteren beweegt... maar de volgende afbeeldingen volgen niet. Als u het opmerkt, keert de tweede afbeelding in de reeks terug naar de bovenkant van de stapel voordat de volgende afbeelding er bovenop knippert.

We moeten de z-index veranderingen. Aanvankelijk hebben alle afbeeldingen zijn z-index: 2. Dat betekent dat de stapelvolgorde moet gaan...

Our eyes 👀 --> 3rd (2) | 2nd (2) | 1st (2)

We schuiven de derde afbeelding en werken deze bij z-index om deze bestelling te krijgen:

Our eyes 👀 --> 2nd (2) | 1st (2) | 3rd (1)

We doen hetzelfde met de tweede:

Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)

…en de eerste:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

Dat doen we en alles lijkt in orde te zijn. Maar in werkelijkheid is het dat niet! Wanneer de eerste afbeelding naar achteren wordt verplaatst, begint de derde afbeelding een nieuwe iteratie, wat betekent dat deze terugkeert naar z-index: 2:

Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)

Dus in werkelijkheid hadden we nooit alle beelden bij z-index: 2 helemaal niet! Wanneer de afbeeldingen niet bewegen (dwz het "niet bewegen" deel van de animatie) zal de z-index is 1. Als we de derde afbeelding verschuiven en deze bijwerken z-index waarde van 2 naar 1, het blijft bovenaan! Wanneer alle afbeeldingen hetzelfde hebben z-index, de laatste in de bronvolgorde - in dit geval onze derde afbeelding - staat bovenaan de stapel. Het schuiven van de derde afbeelding resulteert in het volgende:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

De derde afbeelding staat nog steeds bovenaan en direct daarna verplaatsen we de tweede afbeelding naar boven wanneer de animatie opnieuw begint om z-index: 2:

Our eyes 👀 --> 2nd (2) | 3rd (1) | 1st (1)

Zodra we het verschuiven, krijgen we:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

Dan springt de eerste afbeelding bovenaan:

Our eyes 👀 --> 1st(2) | 3rd (1) | 2nd (1)

Oké, ik ben verdwaald. Dan klopt alle logica niet?

Ik weet het, het is verwarrend. Maar onze logica is niet helemaal verkeerd. We hoeven alleen de animatie een beetje te corrigeren om alles te laten werken zoals we willen. De truc is om de z-index.

Laten we de situatie nemen waarin de derde afbeelding bovenaan staat:

Our eyes 👀 -->  3rd (2) | 2nd (1) | 1st (1)

We zagen dat de derde afbeelding werd verschoven en gewijzigd z-index houdt het er bovenop. Wat we moeten doen is het updaten van de z-index van de tweede afbeelding. Dus voordat we de derde afbeelding van het kaartspel wegschuiven, werken we de z-index van de tweede afbeelding naar 2.

Met andere woorden, we resetten de z-index van de tweede afbeelding voordat de animatie eindigt.

Diagrammen van de delen van de animatie met indicatoren voor waar de z-index wordt verhoogd of verlaagd.
CSS Oneindige schuifregelaar die door polaroidafbeeldingen bladert

Het groene plusteken staat voor toenemend z-index naar 2, en het rode minteken correleert met z-index: 1. De tweede afbeelding begint met z-index: 2, dan updaten we het naar 1 wanneer het van het dek wegglijdt. Maar voordat de eerste afbeelding van het deck wegglijdt, veranderen we de z-index van de tweede afbeelding terug naar 2. Dit zorgt ervoor dat beide afbeeldingen hetzelfde hebben z-index, maar toch blijft de derde bovenaan staan ​​omdat deze later in de DOM verschijnt. Maar na de derde afbeelding dia's en zijn z-index wordt bijgewerkt, gaat het naar beneden.

Dit tweederde door de animatie, dus laten we onze keyframes dienovereenkomstig bijwerken:

@keyframes slide {
  0%     { transform: translateX(0%);   z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  66.33% { transform: translateX(0%);   z-index: 1; }
  66.34% { transform: translateX(0%);   z-index: 2; } /* and also here */
  100%   { transform: translateX(0%);   z-index: 2; }  
}

Iets beter, maar nog steeds niet heel daar. Er is nog een probleem...

Oh nee, dit houdt nooit op!

Maakt u zich geen zorgen, we gaan de hoofdframes niet nog een keer wijzigen, omdat dit probleem zich alleen voordoet als het om de laatste afbeelding gaat. We kunnen speciaal voor de laatste afbeelding een "speciale" keyframe-animatie maken om dingen op te lossen.

Als de eerste afbeelding bovenaan staat, hebben we de volgende situatie:

Our eyes 👀 -->  1st (2) | 3rd (1) | 2nd (1)

Gezien de vorige aanpassing die we hebben gemaakt, springt de derde afbeelding bovenaan voordat de eerste afbeelding verschuift. Het gebeurt alleen in deze situatie omdat de volgende afbeelding die na de eerste afbeelding komt, de is laatste afbeelding die een hogere orde heeft in de DOM. De rest van de afbeeldingen zijn prima, want die hebben we Ndan N - 1, dan gaan we van 3 naar 2 en 2 naar 1… maar dan gaan we van 1 naar N.

Om dat te voorkomen, gebruiken we de volgende keyframes voor de laatste afbeelding:

@keyframes slide-last {
  0%     { transform: translateX(0%);   z-index: 2;}
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  83.33% { transform: translateX(0%);   z-index: 1; }
  83.34% { transform: translateX(0%);   z-index: 2; } /* and also here */
  100%   { transform: translateX(0%);   z-index: 2; }
}

We resetten de z-index waarde 5/6 door de animatie (in plaats van tweederde), dat is wanneer de eerste afbeelding van de stapel is. We zien dus geen springen!

TADA! Onze oneindige slider is nu perfect! Hier is onze definitieve code in al zijn glorie:

.gallery > img {
  animation: slide 6s infinite;
}
.gallery > img:last-child {
  animation-name: slide-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; } 
.gallery > img:nth-child(3) { animation-delay: -4s; }

@keyframes slide {
  0% { transform: translateX(0%); z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } 
  33.34% { transform: translateX(0%); z-index: 1; }
  66.33% { transform: translateX(0%); z-index: 1; }
  66.34% { transform: translateX(0%); z-index: 2; } 
  100% { transform: translateX(0%); z-index: 2; }
}
@keyframes slide-last {
  0% { transform: translateX(0%); z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; }
  33.34% { transform: translateX(0%); z-index: 1; }
  83.33% { transform: translateX(0%); z-index: 1; }
  83.34% { transform: translateX(0%); z-index: 2; } 
  100%  { transform: translateX(0%); z-index: 2; }
}

Ondersteuning van een willekeurig aantal afbeeldingen

Nu onze animatie voor drie afbeeldingen werkt, laten we deze voor elk nummer laten werken (N) van afbeeldingen. Maar eerst kunnen we ons werk een beetje optimaliseren door de animatie op te splitsen om redundantie te voorkomen:

.gallery > img {
  z-index: 2;
  animation: 
    slide 6s infinite,
    z-order 6s infinite steps(1);
}
.gallery > img:last-child {
  animation-name: slide, z-order-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; } 
.gallery > img:nth-child(3) { animation-delay: -4s; }

@keyframes slide {
  16.67% { transform: translateX(120%); }
  33.33% { transform: translateX(0%); }
}
@keyframes z-order {
  16.67%,
  33.33% { z-index: 1; }
  66.33% { z-index: 2; }
}
@keyframes z-order-last {
  16.67%,
  33.33% { z-index: 1; }
  83.33% { z-index: 2; }
}

Veel minder code nu! We maken een animatie voor het glijdende gedeelte en een andere voor het z-index updates. Merk op dat we gebruiken steps(1) op de z-index animatie. Dat komt omdat ik het abrupt wil veranderen z-index waarde, in tegenstelling tot de glijdende animatie waar we een vloeiende beweging willen.

Nu de code gemakkelijker te lezen en te onderhouden is, hebben we een beter zicht om uit te zoeken hoe we een willekeurig aantal afbeeldingen kunnen ondersteunen. Wat we moeten doen, is de animatievertragingen en de percentages van de keyframes bijwerken. De vertraging is eenvoudig omdat we exact dezelfde lus kunnen gebruiken die we in het vorige artikel hebben gemaakt om meerdere afbeeldingen in de ronde schuifregelaar te ondersteunen:

@for $i from 2 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
    animation-delay: calc(#{(1 - $i)/$n}*6s);
  }
}

Dat betekent dat we van vanilla CSS naar Sass gaan. Vervolgens moeten we ons voorstellen hoe de tijdlijn schaalt N afbeeldingen. Laten we niet vergeten dat de animatie in drie fasen verloopt:

Toont de drie delen van de animatie in een reeks lijnen met pijlen.
CSS Oneindige schuifregelaar die door polaroidafbeeldingen bladert

Na "naar rechts schuiven" en "naar links schuiven" moet de afbeelding blijven staan ​​totdat de rest van de afbeeldingen de reeks heeft doorlopen. Het gedeelte "niet bewegen" moet dus evenveel tijd in beslag nemen als (N - 1) als "naar rechts schuiven" en "naar links schuiven". En binnen één iteratie, N afbeeldingen zullen verschuiven. Dus, "schuif naar rechts" en "schuif naar links" nemen beide 100%/N van de totale animatietijdlijn. Het beeld glijdt weg van de stapel bij (100%/N)/2 en glijdt terug naar 100%/N .

We kunnen dit wijzigen:

@keyframes slide {
  16.67% { transform: translateX(120%); }
  33.33% { transform: translateX(0%); }
}

…naar dit:

@keyframes slide {
  #{50/$n}%  { transform: translateX(120%); }
  #{100/$n}% { transform: translateX(0%); }
}

Als we vervangen N Met 3, we krijgen 16.67% en 33.33% wanneer er zijn 3 afbeeldingen in de stapel. Het is dezelfde logica met de stapelvolgorde waar we dit zullen hebben:

@keyframes z-order {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  66.33% { z-index: 2; }
}

We moeten nog steeds de update uitvoeren 66.33% punt. Dat zou moeten zijn waar het beeld zijn reset uitvoert z-index voor het einde van de animatie. Tegelijkertijd begint het volgende beeld te schuiven. Omdat het glijdende deel duurt 100%/N, de reset zou moeten gebeuren om 100% - 100%/N:

@keyframes z-order {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  #{100 - 100/$n}% { z-index: 2; }
}

Maar voor onze z-order-last animatie werkt, zou het iets later in de reeks moeten gebeuren. Weet je nog de oplossing die we voor de laatste afbeelding hebben gedaan? Het resetten van de z-index waarde moet plaatsvinden wanneer de eerste afbeelding uit de stapel is en niet wanneer deze begint te verschuiven. We kunnen dezelfde redenering hier gebruiken in onze keyframes:

@keyframes z-order-last {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  #{100 - 50/$n}% { z-index: 2; }
}

We zijn klaar! Dit is wat we krijgen als we vijf afbeeldingen gebruiken:

We kunnen een vleugje rotatie toevoegen om het wat exclusiever te maken:

Het enige wat ik deed is toevoegen rotate(var(--r)) aan de transform eigendom. Binnen de lus, --r wordt gedefinieerd met een willekeurige hoek:

@for $i from 1 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
    --r: #{(-20 + random(40))*1deg}; /* a random angle between -20deg and 20deg */
  }
}

De rotatie zorgt voor kleine storingen, omdat we soms sommige afbeeldingen naar de achterkant van de stapel kunnen zien springen, maar dat is niet erg.

Afsluiten

Dat allemaal z-index werk was een grote evenwichtsoefening, toch? Als je voor deze oefening niet zeker wist hoe de stapelvolgorde werkt, dan heb je nu waarschijnlijk een veel beter idee! Als je sommige uitleg moeilijk te volgen vond, raad ik je ten zeerste aan om het artikel nog eens te lezen en breng dingen in kaart met potlood en papier. Probeer elke stap van de animatie te illustreren met een ander aantal afbeeldingen om de truc beter te begrijpen.

De vorige keer hebben we een paar geometrietrucs gebruikt om een ​​cirkelvormige schuifregelaar te maken die na een volledige reeks terugdraait naar de eerste afbeelding. Deze keer hebben we een vergelijkbare truc bereikt met behulp van z-index. In beide gevallen hebben we geen van de afbeeldingen gedupliceerd om een ​​doorlopende animatie te simuleren, en evenmin hebben we JavaScript gebruikt om te helpen bij de berekeningen.

De volgende keer gaan we 3D-schuifregelaars maken. Blijf kijken!

Tijdstempel:

Meer van CSS-trucs