Bild-Slider (auch Karussells genannt) sind allgegenwärtig. Es gibt viele CSS-Tricks, um den üblichen Slider zu erstellen, bei dem die Bilder von links nach rechts (oder umgekehrt) gleiten. Dasselbe gilt für die vielen JavaScript-Bibliotheken da draußen, die schicke Slider mit komplexen Animationen erstellen. All das werden wir in diesem Beitrag nicht tun.
In einer kleinen Artikelreihe werden wir einige schicke und ungewöhnliche reine CSS-Slider erkunden. Wenn Sie des immergleichen klassischen Sliders überdrüssig sind, dann sind Sie hier genau richtig!
CSS Sliders Serie
Für diesen ersten Artikel beginnen wir mit etwas, das ich den "kreisförmigen rotierenden Bilder-Slider" nenne.
Cool, oder? Lassen Sie uns den Code zerlegen!
Der HTML-Markup
Wenn Sie meiner Serie von schicken Bilddekorationen oder CSS Grid und benutzerdefinierten Formen gefolgt sind, dann wissen Sie, dass meine erste Regel ist, mit dem kleinstmöglichen HTML zu arbeiten. Ich bemühe mich immer, CSS-Lösungen zu finden, bevor ich meinen Code mit vielen <div>s und anderem Kram überlade.
Die gleiche Regel gilt hier – unser Code ist nichts weiter als eine Liste von Bildern in einem Container.
Nehmen wir an, wir arbeiten mit vier Bildern
<div class="gallery">
<img src="" alt="">
<img src="" alt="">
<img src="" alt="">
<img src="" alt="">
</div>
Das war's! Nun kommen wir zum interessanten Teil des Codes. Aber zuerst tauchen wir tief ein, um die Logik zu verstehen, wie unser Slider funktioniert.
Wie funktioniert es?
Hier ist ein Video, in dem ich overflow: hidden aus dem CSS entferne, damit wir besser verstehen können, wie sich die Bilder bewegen.
Es ist, als ob unsere vier Bilder auf einem großen Kreis platziert sind, der sich gegen den Uhrzeigersinn dreht.

Alle Bilder haben die gleiche Größe (bezeichnet mit S in der Abbildung). Beachten Sie den blauen Kreis, der der Kreis ist, der die Mitte aller Bilder schneidet und einen Radius (R) hat. Diesen Wert benötigen wir später für unsere Animation. R ist gleich 0,707 * S. (Die Geometrie, die uns diese Gleichung liefert, werde ich überspringen.)
Schreiben wir etwas CSS!
Wir werden CSS Grid verwenden, um alle Bilder im selben Bereich übereinander zu platzieren.
.gallery {
--s: 280px; /* control the size */
display: grid;
width: var(--s);
aspect-ratio: 1;
padding: calc(var(--s) / 20); /* we will see the utility of this later */
border-radius: 50%;
}
.gallery > img {
grid-area: 1 / 1;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: inherit;
}
Bisher nichts allzu Kompliziertes. Der knifflige Teil ist die Animation.
Wir sprachen davon, einen großen Kreis zu drehen, aber in Wirklichkeit werden wir jedes Bild einzeln drehen, um die Illusion eines großen rotierenden Kreises zu erzeugen. Definieren wir also eine Animation, m, und wenden wir sie auf die Bildelemente an.
.gallery > img {
/* same as before */
animation: m 8s infinite linear;
transform-origin: 50% 120.7%;
}
@keyframes m {
100% { transform: rotate(-360deg); }
}
Der Haupttrick beruht auf dieser hervorgehobenen Zeile. Standardmäßig ist die CSS-Eigenschaft transform-origin gleich center (oder 50% 50%), wodurch sich das Bild um seine Mitte dreht. Aber das brauchen wir nicht. Wir brauchen, dass sich das Bild um die Mitte des *großen Kreises* dreht, der unsere Bilder enthält, daher der neue Wert für transform-origin.
Da R gleich 0,707 * S ist, können wir sagen, dass R gleich 70,7 % der Bildgröße ist. Hier ist eine Abbildung, die veranschaulicht, wie wir auf den Wert 120,7 % gekommen sind.

Lassen Sie uns die Animation ausführen und sehen, was passiert.
Ich weiß, ich weiß. Das Ergebnis ist weit von dem entfernt, was wir wollen, aber eigentlich sind wir sehr nah dran. Es sieht vielleicht so aus, als gäbe es nur ein Bild, aber vergessen Sie nicht, dass wir alle Bilder übereinander gestapelt haben. Alle drehen sich gleichzeitig und nur das oberste Bild ist sichtbar. Was wir brauchen, ist, die Animation jedes Bildes zu verzögern, um diese Überlappung zu vermeiden.
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
Die Dinge werden schon besser!
Wenn wir den Überlauf am Container ausblenden, können wir bereits einen Slider sehen, aber wir werden die Animation noch ein wenig aktualisieren, damit jedes Bild für kurze Zeit sichtbar bleibt, bevor es weiterzieht.
Wir werden unsere Animations-Keyframes aktualisieren, um genau das zu tun.
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% { transform: rotate(-360deg); }
}
Für jedes 90deg (360deg/4, wobei 4 die Anzahl der Bilder ist) fügen wir eine kleine Pause ein. Jedes Bild bleibt für 5 % der Gesamtdauer sichtbar, bevor wir zum nächsten gleiten (27 %-22 %, 52 %-47 % usw.). Ich werde die animation-timing-function mithilfe einer cubic-bezier()-Funktion aktualisieren, um die Animation etwas schicker zu machen.
Jetzt ist unser Slider perfekt! Naja, fast perfekt, denn uns fehlt noch der letzte Schliff: der bunte Kreisrand, der sich um unsere Bilder dreht. Wir können dafür ein Pseudoelement auf dem .gallery Wrapper verwenden.
.gallery {
padding: calc(var(--s) / 20); /* the padding is needed here */
position: relative;
}
.gallery::after {
content: "";
position: absolute;
inset: 0;
padding: inherit; /* Inherits the same padding */
border-radius: 50%;
background: repeating-conic-gradient(#789048 0 30deg, #DFBA69 0 60deg);
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask-composite: exclude;
}
.gallery::after,
.gallery >img {
animation: m 8s infinite cubic-bezier(.5, -0.2, .5, 1.2);
}
Ich habe einen Kreis mit einem wiederholenden konischen Gradienten für den Hintergrund erstellt, während ich einen Maskierungs-Trick verwendet habe, der nur den gepolsterten Bereich anzeigt. Dann wende ich darauf die gleiche Animation an, die wir für die Bilder definiert haben.
Wir sind fertig! Wir haben einen coolen kreisförmigen Slider.
Fügen wir mehr Bilder hinzu
Mit vier Bildern zu arbeiten ist gut, aber es wäre besser, wenn wir es auf jede beliebige Anzahl von Bildern skalieren könnten. Schließlich ist das der Zweck eines Bild-Sliders. Wir sollten N Bilder berücksichtigen können.
Dazu machen wir den Code generischer, indem wir Sass einführen. Zuerst definieren wir eine Variable für die Anzahl der Bilder ($n) und aktualisieren jeden Teil, in dem wir die Anzahl der Bilder (4) hartcodiert haben.
Beginnen wir mit den Verzögerungen.
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
Die Formel für die Verzögerung lautet (1 - $i)*duration/$n, was uns den folgenden Sass-Loop ergibt.
@for $i from 2 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
animation-delay: calc(#{(1 - $i) / $n} * 8s);
}
}
Wir können die Dauer auch zu einer Variablen machen, wenn wir wirklich wollen. Aber lassen Sie uns mit der Animation fortfahren.
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% {transform: rotate(-360deg); }
}
Vereinfachen wir es, um das Muster besser zu sehen.
@keyframes m {
0% { transform: rotate(0); }
25% { transform: rotate(-90deg); }
50% { transform: rotate(-180deg); }
75% { transform: rotate(-270deg); }
100% { transform: rotate(-360deg); }
}
Der Schritt zwischen jedem Zustand beträgt 25 % – das ist 100 %/4 – und wir fügen einen Winkel von -90deg hinzu – das ist -360deg/4. Das bedeutet, wir können unseren Loop stattdessen so schreiben:
@keyframes m {
0% { transform: rotate(0); }
@for $i from 1 to $n {
#{($i / $n) * 100}% { transform: rotate(#{($i / $n) * -360}deg); }
}
100% { transform: rotate(-360deg); }
}
Da jedes Bild 5 % der Animation einnimmt, ändern wir dies.
#{($i / $n) * 100}%
…mit diesem.
#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}%
Es sei darauf hingewiesen, dass 5 % ein beliebiger Wert ist, den ich für dieses Beispiel gewählt habe. Wir können ihn auch zu einer Variablen machen, um zu steuern, wie lange jedes Bild sichtbar sein soll. Ich überspringe das der Einfachheit halber, aber als Hausaufgabe können Sie versuchen, es zu tun und Ihre Implementierung in den Kommentaren zu teilen!
@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); }
}
Der letzte Teil ist die Aktualisierung von transform-origin. Wir benötigen einige Geometrie-Tricks. Unabhängig von der Anzahl der Bilder ist die Konfiguration immer dieselbe. Wir haben unsere Bilder (kleine Kreise), die in einem großen Kreis platziert sind, und wir müssen den Wert des Radius, R, ermitteln.

Sie wollen wahrscheinlich keine langweilige Geometrie-Erklärung, also hier ist, wie wir R finden.
R = S / (2 * sin(180deg / N))
Wenn wir das als Prozentsatz ausdrücken, erhalten wir.
R = 100% / (2 * sin(180deg / N)) = 50% / sin(180deg / N)
…was bedeutet, dass der Wert von transform-origin gleich ist.
transform-origin: 50% (50% / math.sin(180deg / $n) + 50%);
Wir sind fertig! Wir haben einen Slider, der mit jeder Anzahl von Bildern funktioniert!
Lassen Sie uns neun Bilder hineinwerfen.
Fügen Sie beliebig viele Bilder hinzu und aktualisieren Sie die Variable $n mit der Gesamtzahl der Bilder.
Zusammenfassung
Mit ein paar Tricks, die CSS-Transforms und Standardgeometrie verwenden, haben wir einen schönen kreisförmigen Slider erstellt, der nicht viel Code benötigt. Das Coole an diesem Slider ist, dass wir uns nicht darum kümmern müssen, die Bilder zu duplizieren, um die unendliche Animation aufrechtzuerhalten, da wir einen Kreis haben. Nach einer vollen Drehung kehren wir zum ersten Bild zurück!
Für alle, die mehr Details zum Geometrie-Teil wünschen, hier ist eine Abbildung.
Super coole Technik, so viele Nuggets in dieser einzelnen Demo! Danke fürs Teilen.
Schön. Einfach. Weniger ist besser.
Mir fällt auf, dass jedes Bild ein wenig über den sichtbaren Bereich hinaus rotiert und dann zurückkehrt, um genau hineinzupassen. Was verursacht das?
Das ist die Cubic Bezier. Irgendwo im Artikel ändere ich die Timing-Funktion von linear zu cubic-bezier().
Interessant. Ich vermutete die Cubic Bezier, aber ich wusste nicht, dass eine Timing-Funktion die Reihenfolge der Frames ändern kann. Ich dachte, sie beeinflusst nur die Dauer jedes Frames.
Das ist genial.
Einer der besten Tricks, die mir begegnet sind. Großartige Arbeit, wunderschön vereinfacht.
Was passiert, wenn die Anzahl der Bilder dynamisch ist? Wie würde das Nth-ing der Bilder n Bilder berücksichtigen?
Ich frage mich, ob ein Quadrat ähnlich oder sogar einfacher wäre?
Hat jemand mit einem perfekten Quadrat für die Bilder experimentiert?