Ich habe kürzlich gezeigt, wie komplexe CSS-Animationen mit cubic-bezier() erstellt werden können und wie man dasselbe für CSS-Übergänge tut. Ich konnte komplexe Hover-Effekte erstellen, ohne auf Keyframes zurückgreifen zu müssen. In diesem Artikel zeige ich Ihnen, wie Sie *noch* komplexere CSS-Übergänge erstellen.
Dieses Mal verwenden wir die `@property`-Funktion. Sie wird derzeit nur in Chrome-basierten Browsern unterstützt, aber wir können damit spielen und demonstrieren, wie auch sie zur Erstellung komplexer Animationen verwendet werden kann.
Ich empfehle dringend, meinen vorherigen Artikel zu lesen, da ich auf einige Konzepte zurückgreifen werde, die ich dort detailliert erklärt habe. Bitte beachten Sie auch, dass die Demos in diesem Artikel am besten in Chromium-basierten Browsern angezeigt werden, da die Unterstützung für `@property` noch begrenzt ist.
Beginnen wir mit einer Demo
Klicken Sie auf den Button (mehr als einmal) und sehen Sie die "magische" Kurve, die wir erhalten. Sie mag auf den ersten Blick trivial erscheinen, da wir einen solchen Effekt mit einigen komplexen Keyframes erzielen können. Aber der Trick ist, dass keine Keyframes darin enthalten sind! Diese Animation wird nur mit einem Übergang durchgeführt.
Großartig, oder? Und das ist erst der Anfang, also tauchen wir ein!
Die Hauptidee
Der Trick im vorherigen Beispiel basiert auf diesem Code
@property --d1 {
syntax: '<number>';
inherits: false;
initial-value: 0;
}
@property --d2 {
syntax: '<number>';
inherits: false;
initial-value: 0;
}
.box {
top: calc((var(--d1) + var(--d2)) * 1%);
transition:
--d1 1s cubic-bezier(0.7, 1200, 0.3, -1200),
--d2 1s cubic-bezier(0.5, 1200, 0.5, -1200);
}
.box:hover {
--d1: 0.2;
--d1: -0.2;
}
Wir definieren zwei benutzerdefinierte Eigenschaften, `--d1` und `--d2`. Dann deklarieren wir die `top`-Eigenschaft für ein `.box`-Element, die die Summe beider Eigenschaften verwendet. Noch nichts Außergewöhnliches – nur `calc()` auf zwei Variablen angewendet.
Die beiden Eigenschaften sind als `
Beachten Sie, dass wir jeder Variablen einen anderen Übergang zuweisen – genauer gesagt, eine andere `timing-function` bei gleicher Dauer. Es handelt sich tatsächlich um eine andere *sinusförmige Kurve* für beide Variablen, ein Thema, das ich in meinem vorherigen Artikel ausführlich behandelt habe.
Von dort aus ändern sich die Eigenschaftswerte, wenn das `.box` gehovert wird, was die Animation auslöst. Aber warum erhalten wir das Ergebnis, das wir in der Demo sehen?
Es geht nur um Mathematik. Wir addieren zwei Funktionen, um eine dritte zu erstellen. Für `--d1` haben wir eine Funktion (nennen wir sie F1); für `--d2` haben wir eine andere (nennen wir sie F2). Das bedeutet, der Wert von `top` ist F1 + F2.
Ein Beispiel zur besseren Veranschaulichung
Die ersten beiden Übergänge veranschaulichen jede Variable einzeln. Der dritte ist die Summe von ihnen. Stellen Sie sich vor, dass wir in jedem Schritt der Animation den Wert beider Variablen nehmen und sie addieren, um jeden Punkt auf der endgültigen Kurve zu erhalten.
Versuchen wir ein weiteres Beispiel
Dieses Mal kombinieren wir zwei parabolische Kurven, um eine ... nun, ich kenne ihren Namen nicht, aber es ist eine weitere komplexe Kurve!
Dieser Trick beschränkt sich nicht nur auf parabolische und sinusförmige Kurven. Er funktioniert mit jeder Art von Timing-Funktion, auch wenn das Ergebnis nicht immer eine komplexe Kurve ist.
Dieses Mal
- `--d1` geht von `0` auf `30` mit einer `ease-in`-Timing-Funktion
- `--d2` geht von `0` auf `-20` mit einer `ease-out`-Timing-Funktion
Das Ergebnis? Der `top`-Wert geht von `0` auf `10` (`30-20`) mit einer benutzerdefinierten Timing-Funktion (der Summe von `ease-in` und `ease-out`).
Wir erhalten in diesem Fall keinen komplexen Übergang – es dient eher dazu, die Tatsache zu veranschaulichen, dass es sich um eine allgemeine Idee handelt, die nicht nur auf `cubic-bezier()` beschränkt ist.
Ich denke, es ist Zeit für eine interaktive Demo.
Sie müssen nur ein paar Variablen anpassen, um Ihren eigenen komplexen Übergang zu erstellen. Ich weiß, dass `cubic-bezier()` knifflig sein kann, daher sollten Sie diesen Online-Kurvengenerator verwenden und sich auch auf meinen vorherigen Artikel beziehen.
Hier sind einige Beispiele, die ich gemacht habe





Wie Sie sehen können, können wir zwei verschiedene Timing-Funktionen (erstellt mit `cubic-bezier()`) kombinieren, um eine dritte zu erstellen, die komplex genug ist, um einen schicken Übergang zu erzielen. Die Kombinationen (und Möglichkeiten) sind unbegrenzt!
Im letzten Beispiel wollte ich demonstrieren, wie die Addition zweier entgegengesetzter Funktionen zum logischen Ergebnis einer konstanten Funktion (kein Übergang) führt. Daher die flache Linie.
Fügen wir *mehr* Variablen hinzu!
Dachten Sie, wir würden bei nur zwei Variablen aufhören? Sicherlich nicht! Wir können die Logik auf N Variablen erweitern. Es gibt keine Einschränkung – wir definieren jede mit einer Timing-Funktion und addieren sie.
Ein Beispiel mit drei Variablen
In den meisten Fällen reichen zwei Variablen aus, um eine schicke Kurve zu erstellen, aber es ist gut zu wissen, dass der Trick auf mehr Variablen ausgedehnt werden kann.
Können wir Variablen subtrahieren, multiplizieren und dividieren?
Natürlich! Wir können die gleiche Idee auch erweitern, um mehr Operationen zu berücksichtigen. Wir können addieren, subtrahieren, multiplizieren, dividieren – und sogar eine komplexe Formel zwischen Variablen anwenden.
Hier multiplizieren wir Werte


Wir können auch eine Variable verwenden und sie mit sich selbst multiplizieren, um eine quadratische Funktion zu erhalten!
Lassen Sie uns mehr Spaß hinzufügen, indem wir `min()`/`max()` einführen, um eine `abs()`-Funktion zu simulieren
Beachten Sie, dass wir im zweiten Feld niemals höher als der Mittelpunkt auf der y-Achse kommen, da `top` immer ein positiver Wert ist. (Ich habe `margin-top` hinzugefügt, um die Mitte der Box als Referenz für 0 zu verwenden.)


Ich werde nicht auf alle mathematischen Details eingehen, aber Sie können sich die Möglichkeiten vorstellen, jede Art von Timing-Funktion zu erstellen. Alles, was wir tun müssen, ist, die richtige Formel zu finden, entweder mit einer Variablen oder durch die Kombination mehrerer Variablen.
Unser ursprünglicher Code kann verallgemeinert werden
@property --d1 { /* we do the same for d2 .. dn */
syntax: '<number>';
inherits: false;
initial-value: i1; /* the initial value can be different for each variable */
}
.box {
--duration: 1s; /* the same duration for all */
property: calc(f(var(--d1),var(--d2), .. ,var(--dn))*[1UNIT]);
transition:
--d1 var(--duration) cubic-bezier( ... ),
--d2 var(--duration) cubic-bezier( ... ),
/* .. */
--dn var(--duration) cubic-bezier( ... );
}
.box:hover {
--d1:f1;
--d2:f2;
/* .. */
--dn:f3;
}
Dies ist Pseudocode, um die Logik zu veranschaulichen
- Wir verwenden `@property`, um numerische benutzerdefinierte Eigenschaften mit jeweils einem Anfangswert zu definieren.
- Jede Variable hat ihre eigene Timing-Funktion, aber die gleiche Dauer.
- Wir definieren eine `f`-Funktion, die die zwischen den Variablen verwendete Formel ist. Die Funktion liefert eine Zahl, die wir zum Multiplizieren der entsprechenden Einheit verwenden. All dies läuft in `calc()` und wird auf die Eigenschaft angewendet.
- Wir aktualisieren den Wert jeder Variablen beim Hovern (oder Umschalten oder was auch immer).
Unter diesen Bedingungen wechselt die Eigenschaft von `f(i1,i2,…,in)` zu `f(f1,f2,..,fn)` mit einer benutzerdefinierten Timing-Funktion.
Verkettung von Timing-Funktionen
Wir sind an dem Punkt angelangt, an dem wir eine komplexe Timing-Funktion durch die Kombination einfacherer erstellen konnten. Versuchen wir eine weitere Idee, die uns komplexere Timing-Funktionen ermöglicht: **das Verketten von Timing-Funktionen**.
Der Trick besteht darin, die Übergänge sequenziell mit der Eigenschaft `transition-delay` auszuführen. Schauen wir uns die interaktive Demo noch einmal an und wenden wir eine Verzögerung auf eine der Variablen an.
Wir verketten Timing-Funktionen, anstatt sie zu addieren, um eine *weitere* Möglichkeit zu schaffen, komplexere Timing-Funktionen zu erstellen! Mathematisch gesehen ist es immer noch eine Summe, aber da die Übergänge nicht gleichzeitig ausgeführt werden, summieren wir eine Funktion mit einer Konstanten, was die Verkettung simuliert.
Stellen Sie sich nun den Fall mit N Variablen vor, die inkrementell verzögert werden. Nicht nur können wir auf diese Weise komplexe Übergänge erstellen, sondern wir haben auch genügend Flexibilität, um komplexe *Zeitpläne* zu erstellen.
Hier ist ein lustiger Hover-Effekt, den ich mit dieser Technik erstellt habe
Sie werden hier keine Keyframes finden. Eine kleine Actionszene ist komplett mit einem Element und einem CSS-Übergang aufgebaut.
Hier ist eine realistische Pendelanimation mit der gleichen Idee
Oder wie wäre es mit einem Ball, der natürlich abprallt
Oder vielleicht ein Ball, der entlang einer Kurve rollt
Sehen Sie das? Wir haben gerade komplexe Animationen ohne einen einzigen Keyframe im Code erstellt!
Das ist ein Abschluss!
Ich hoffe, Sie haben drei Kernpunkte aus diesem Artikel und dem vorherigen Artikel mitgenommen
- Wir können parabolische und sinusförmige Kurven mit `cubic-bezier()` erhalten, die es uns ermöglichen, komplexe Übergänge ohne Keyframes zu erstellen.
- Wir können mehr Kurven erstellen, indem wir verschiedene Timing-Funktionen mit benutzerdefinierten Eigenschaften und `calc()` kombinieren.
- Wir können die Kurven mithilfe von `transition-delay` verketten, um einen komplexen Zeitplan zu erstellen.
Dank dieser drei Funktionen haben wir keine Grenzen bei der Erstellung komplexer Animationen.
Es funktioniert nur in Chrome. Aber sooo cool!
Nein: Safari, Firefox (Gute Nachrichten ... beide rüsten offiziell auf ... wann aber ... ?)
Ja: Chrome* (… und *basierte Browser, z.B. Brave), Edge, Opera