Apple Music hat diese „Spatial Audio“-Funktion, bei der die Richtung der Musik in Ihren Kopfhörern auf der Position des Geräts basiert. Es ist schwierig zu erklären, wie raffiniert das ist. Aber darum geht es mir hier nicht.
Ich öffnete die Apple Music App und sah eine hervorgehobene Playlist mit Treffer-Songs, die Spatial Audio unterstützen. Das Cover dafür ist dieser leuchtend pinke Behälter, der viele übereinander gestapelte Boxen enthält. Die Boxen animieren nacheinander, blenden in der Mitte des Behälters ein und verblassen dann, während sie sich auf die Größe des Behälters skalieren. Wie eine Endlosschleife.

Cool! Ich wusste, dass ich es in CSS nachbilden musste. Also habe ich es getan.
So funktioniert es…
Das Markup
Ich begann mit dem HTML. Wir brauchen offensichtlich einen Behälter, den wir definieren müssen, sowie beliebig viele Boxen, die wir animieren wollen. Ich habe mich für zehn Boxen im Behälter entschieden.
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<!-- etc. -->
</div>
Das ist buchstäblich alles für das HTML. Wir können direkt zum CSS übergehen!
Styling des Containers
Nichts Besonderes hier. Ich habe ungefähre Abmessungen basierend auf dem, was ich in Apple Music gesehen habe, gemessen, was 315px × 385px ergab. Dann habe ich einen Screenshot des Covers gemacht und ihn in meiner Bildbearbeitungs-App geöffnet, um die hellstmögliche Farbe zu erhalten, die sich um die Außenkanten des Containers befindet. Mein Farbwähler landete auf #eb5bec.
.container {
background-color: #eb5bec;
height: 315px;
width: 385px;
}
Während ich das tat, wusste ich, dass ich dies wahrscheinlich zu einem Grid-Container machen wollte, um die Boxen und andere Elemente in der Mitte auszurichten. Ich vermutete auch, dass die Boxen selbst von der Mitte des Containers ausgehen und übereinander gestapelt werden würden, was eine absolute Positionierung bedeutet. Das bedeutet auch, dass der Container eine relative Positionierung haben sollte, um sie einzudämmen.
.container {
background-color: #eb5bec;
height: 315px;
position: relative;
width: 385px;
}
Und da die Boxen von der Mitte aus starten sollen, können wir das mit Grid erreichen.
.container {
background-color: #eb5bec;
display: grid;
height: 315px;
place-items: center;
position: relative;
width: 385px;
}
Wenn die Boxen im Container nach außen wachsen, besteht die Gefahr, dass sie über den Container hinausgehen. Besser, jeden möglichen Überlauf verstecken.
.container {
background-color: #eb5bec;
height: 315px;
overflow: hidden;
position: relative;
width: 385px;
}
Ich bemerkte auch einige abgerundete Ecken, also fügen wir das gleich hinzu.
.container {
background-color: #eb5bec;
border-radius: 16px;
height: 315px;
position: relative;
width: 385px;
}
Bis jetzt alles gut!
Styling der Boxen
Wir haben 10 .box-Elemente im Markup und wollen sie übereinander stapeln. Ich begann mit einer absoluten Positionierung und gab ihnen dann eine Größe von 100px Quadrat. Dann habe ich das Gleiche mit meiner Bildbearbeitungs-App gemacht, um den dunkelsten Farbwert einer Box zu ermitteln, der #471e45 war.
.box {
background: #471e45;
height: 100px;
position: absolute;
width: 100px;
}
Die Boxen scheinen beim Wachsen zu verblassen. Das ermöglicht, dass eine Box durch die andere hindurchscheint, also machen wir sie anfangs opak.
.box {
background: #471e45;
height: 100px;
opacity: 0.5;
position: absolute;
width: 100px;
}
Gut, gut. Wir können nicht alle Boxen sehen, da sie übereinander gestapelt sind, aber wir machen Fortschritte!
Erstellen der Animation
Bereit, einige @keyframes zu schreiben? Wir machen das super einfach, von 0 bis 100% ohne Zwischenschritte. Wir brauchen nicht einmal diese Prozentsätze!
@keyframes grow {
from {
/* do stuff */
}
to {
/* do stuff */
}
}
Konkret wollen wir, dass zwei Dinge von Anfang bis Ende passieren:
- Die Boxen gehen von unserem Start-Deckkraftwert von
0.5auf0(vollständig transparent). - Die Boxen skalieren bis zu den Rändern des Containers.
@keyframes grow {
from {
opacity: 0.5;
transform: scale(0);
}
to {
opacity: 0;
transform: scale(3.85);
}
}
Wie bin ich auf die Skalierung der Boxen um 3.85 gekommen? Unsere Boxen sind 100px im Quadrat und der Container ist 385px hoch. Ein Wert von 3.85 bringt die Boxen auf 385px, während sie vollständig ausblenden, was für eine schöne lineare Animation sorgt, wenn wir dort ankommen.
Wo wir gerade dabei sind…
Anwenden der Animation
Es ist ziemlich einfach, die Animation auf unsere Boxen anzuwenden. Wir müssen nur sicherstellen, dass sie mit einer linearen Timing-Funktion auf unendlicher Basis läuft, damit sie wie der Energizer-Hase ist und immer weiter und weiter und weiter und… läuft.
.box {
animation: grow 10s linear infinite; /* 10s = 10 boxes */
/* etc. */
}
Das gibt uns die gewünschte Animation. Aber! Die Boxen bewegen sich alle gleichzeitig, so dass wir nur eine riesige Box sehen, die wächst.
Wir müssen diese kleinen Kerlchen versetzt animieren. Leider gibt es keine Schleifen in reinem CSS, daher müssen wir jede Box einzeln verzögern. Wir können mit der Festlegung einer benutzerdefinierten Eigenschaft für die Verzögerung beginnen, sie auf eine Sekunde setzen und dann die benutzerdefinierte Eigenschaft auf jeder Instanz neu definieren.
.box {
--delay: 1s;
animation-delay: var(--delay);
/* same as before */
}
.box:nth-child(2) {
--delay: 2s;
}
.box:nth-child(3) {
--delay: 3s;
}
.box:nth-child(4) {
--delay: 4s;
}
.box:nth-child(5) {
--delay: 5s;
}
/* five more times... */
Huzzah!
Weiter so
Das war's! Wir haben gerade den gleichen Effekt wie bei Apple Music nachgebildet. Es gibt ein paar letzte Schliffarbeiten, die wir einfügen könnten, wie den Inhalt und so weiter. Hier ist meine endgültige Version noch einmal.
Ich werbe nicht gerne für mich selbst, aber vor einiger Zeit hatte ich tatsächlich etwas Ähnliches im Sinn! Also dachte ich, wenn den Leuten das gefällt, gefällt ihnen vielleicht auch eine ähnliche Apple-inspirierte Karte, die ich mit WebGL erstellt habe: https://fjolt.com/article/apple-cards-webl-gl-javascript
Ooo, die sind schön!
Wenn Sie alle Verzögerungen auf negative Werte setzen, beginnt es mit dem vollen Effekt, anstatt 10 Sekunden warten zu müssen, bis alles animiert ist.
Ich habe auch herausgefunden, dass man nur den Haupt-Hintergrund setzen und
rgba(0, 0, 0, 0.25)für die Boxen verwenden kann, so dass man die andere Farbe nicht berechnen muss. Ich weiß nicht, ob es genau passt, aber ich denke, es ist nah genug.Habe meine eigene Version mit diesen Updates gemacht: https://svelte.dev/repl/234ce30ccabc4058a1e46013b468ee89?version=3.44.2
Ich liebte diese Animation und wollte es mit nur einem Div versuchen. Es ist fast da, aber definitiv verbesserungsfähig und besser zu keyframen. Wenn ich mehr Zeit habe, werde ich zurückgehen und das ein wenig aufräumen.
Danke für die Inspiration!