Im Jahr 2012 kam Internet Explorer 10 heraus und unterstützte unter anderem endlich CSS-Verläufe und darüber hinaus die Möglichkeit, diese nur mit CSS zu animieren! Damals unterstützte kein anderer Browser dies, aber ich war hoffnungsvoll für die Zukunft.
Leider sind sechs Jahre vergangen und in diesem Bereich hat sich nichts geändert. Edge unterstützt das Animieren von Verläufen mit CSS, genau wie IE 10 damals, aber kein anderer Browser hat dies unterstützt. Und während das Animieren von background-size oder background-position oder der opacity oder Rotation eines darüber liegenden Pseudo-Elements uns weit bringen kann, um coole Effekte zu erzielen, sind diese Workarounds immer noch begrenzt.
Es gibt Effekte, die wir nicht reproduzieren können, ohne viele zusätzliche Elemente oder viele zusätzliche Verläufe hinzuzufügen, wie z. B. den unten gezeigten „Jalousien-Effekt“.

In Edge wird der obige Effekt mit einer Keyframe-animation erzielt
html {
background: linear-gradient(90deg, #f90 0%, #444 0) 50%/ 5em;
animation: blinds 1s ease-in-out infinite alternate;
}
@keyframes blinds {
to {
background-image: linear-gradient(90deg, #f90 100%, #444 0);
}
}
Wenn das WET erscheint, können wir es mit DRY machen mit einem Hauch von Sass
@function blinds($open: 0) {
@return linear-gradient(90deg, #f90 $open*100%, #444 0);
}
html {
background: blinds() 50%/ 5em;
animation: blinds 1s ease-in-out infinite alternate;
}
@keyframes blinds { to { background-image: blinds(1) } }
Während wir den Code, den wir schreiben und den wir später bearbeiten müssen, viel wartungsfreundlicher gemacht haben, haben wir immer noch Wiederholungen im kompilierten CSS und sind durch die Tatsache eingeschränkt, dass wir nur zwischen Stopps mit der gleichen Einheit animieren können — während das Animieren von 0% bis 100% einwandfrei funktioniert, führt der Versuch, 0 oder 0px anstelle von 0% zu verwenden, dazu, dass keine Animation stattfindet. Ganz zu schweigen davon, dass Chrome und Firefox einfach von Orange zu Grau wechseln, ohne jegliche Positionsanimation!
Glücklicherweise haben wir heutzutage eine noch bessere Option: CSS-Variablen!
CSS-Variablen sind von Haus aus nicht animierbar, obwohl wir transition- (aber keine animation-!) Effekte erzielen können, *wenn die Eigenschaft, für die wir sie verwenden, animierbar ist*. Wenn sie beispielsweise in einer transform-Funktion verwendet werden, können wir die transform-Eigenschaft transitionen.
Betrachten wir das Beispiel einer Box, die verschoben und gequetscht wird, wenn eine Checkbox aktiviert ist. Auf dieser Box setzen wir eine transform, die von einem Faktor --f abhängt, der anfänglich 1 ist
.box {
/* basic styles like dimensions and background */
--f: 1;
transform: translate(calc((1 - var(--f))*100vw)) scalex(var(--f));
}
Wenn die Checkbox :checked ist, ändern wir den Wert der CSS-Variable --f zu .5
:checked ~ .box { --f: .5 }
Das Festlegen einer transition auf die .box lässt sie reibungslos von einem Zustand zum anderen übergehen
.box {
/* same styles as before */
transition: transform .3s ease-in;
}
Beachten Sie, dass dies in der aktuellen Version von Edge aufgrund dieses Fehlers nicht wirklich funktioniert.
CSS-Verläufe sind jedoch Hintergrundbilder, die nur in Edge und IE 10+ animierbar sind. Während wir uns also das Leben erleichtern und die Menge an generiertem CSS für Übergänge reduzieren können (wie im folgenden Code zu sehen ist), machen wir in Bezug auf die Erweiterung der Unterstützung immer noch keine Fortschritte.
.blinds {
background: linear-gradient(90deg, #f90 var(--pos, 0%), #444 0) 50%/ 5em;
transition: .3s ease-in-out;
:checked ~ & { --pos: 100%; }
}

Hier kommt Houdini ins Spiel, das es uns ermöglicht, benutzerdefinierte Eigenschaften zu registrieren und sie dann zu animieren. Derzeit wird dies nur von Blink-Browsern hinter dem Flag Experimental Web Platform features unterstützt, aber es erweitert die Unterstützung immerhin ein wenig über Edge hinaus.

Zurück zu unserem Beispiel registrieren wir die benutzerdefinierte Eigenschaft --pos
CSS.registerProperty({
name: '--pos',
syntax: '<length-percentage>',
initialValue: '0%',
inherits: true
});
Beachten Sie, dass bedeutet, dass es nicht nur Längen- und Prozentwerte, sondern auch calc()-Kombinationen davon akzeptiert. Im Gegensatz dazu akzeptiert | nur Längen- und Prozentwerte, aber keine calc()-Kombinationen davon.
Beachten Sie, dass die explizite Angabe von inherits jetzt obligatorisch ist, auch wenn sie in früheren Versionen der Spezifikation optional war.
Dies macht jedoch in Chrome keinen Unterschied, selbst mit aktiviertem Flag, wahrscheinlich weil bei Übergängen die Eigenschaft, deren Wert von der CSS-Variablen abhängt, und nicht die CSS-Variable selbst übergangt wird. Und da wir im Allgemeinen keine Übergänge zwischen zwei Hintergrundbildern in Chrome durchführen können, schlägt dies ebenfalls fehl.
Es funktioniert in Edge, aber es funktionierte auch in Edge ohne Registrierung der --pos-Variable, da Edge uns erlaubt, generell zwischen Verläufen zu wechseln.
Was funktioniert in Blink-Browsern mit aktiviertem Flag, ist eine animation anstelle einer transition.
html {
background: linear-gradient(90deg, #f90 var(--pos, 0%), #444 0) 50%/ 5em;
animation: blinds .85s ease-in-out infinite alternate;
}
@keyframes blinds { to { --pos: 100%; } }
Dies funktioniert jedoch in Edge nicht mehr, da Edge zwar zwischen Gradientenhintergründen animieren kann, dies aber nicht für benutzerdefinierte Eigenschaften tun kann.
Wir müssen also für Edge einen alternativen Ansatz wählen. Hier ist @supports nützlich, da wir nur prüfen müssen, ob eine Eigenschaft mit -ms- Präfix unterstützt wird.
@function grad($pos: 100%) {
@return linear-gradient(90deg, #f90 $pos, #444 0);
}
html {
/* same as before */
@supports (-ms-user-select: none) {
background-image: grad(0%);
animation-name: blinds-alt;
}
}
@keyframes blinds-alt { to { background-image: grad() } }
Stopppositionen sind nicht das Einzige, was wir auf diese Weise animieren können. Dasselbe können wir für den Gradientenwinkel tun. Die Idee dahinter ist ziemlich dieselbe, außer dass unsere animation jetzt keine alternierende mehr ist und wir eine easeInOutBack-Timing-Funktion verwenden.
@function grad($ang: 1turn) {
@return linear-gradient($ang, #f90 50%, #444 0);
}
html {
background: grad(var(--ang, 0deg));
animation: rot 2s cubic-bezier(.68, -.57, .26, 1.65) infinite;
@supports (-ms-user-select: none) {
background-image: grad(0turn);
animation-name: rot-alt;
}
}
@keyframes rot { to { --ang: 1turn; } }
@keyframes rot-alt { to { background-image: grad(); } }
Denken Sie daran, dass wir, genau wie bei den Stopppositionen, in Edge nur zwischen Gradientenwinkeln animieren können, die in der gleichen Einheit ausgedrückt sind. Daher funktioniert das Aufrufen unserer Sass-Funktion mit grad(0deg) anstelle von grad(0turn) nicht.
Und natürlich akzeptiert die CSS-Variable, die wir jetzt verwenden, Winkelwerte anstelle von Längen und Prozentangaben
CSS.registerProperty({
name: '--ang',
syntax: '<angle>',
initialValue: '0deg',
inherits: true
});

Auf ähnliche Weise können wir auch radiale Verläufe animieren. Und das wirklich Coole am CSS-Variablenansatz ist, dass er es uns ermöglicht, verschiedene Komponenten des Verlaufs unterschiedlich zu animieren, was nicht möglich ist, wenn Verläufe als Ganzes animiert werden, wie es Edge tut (weshalb die folgenden Demos in Edge nicht so gut funktionieren).
Nehmen wir an, wir haben den folgenden radial-gradient()
$p: 9%;
html {
--x: #{$p};
--y: #{$p};
background: radial-gradient(circle at var(--x) var(--y), #f90, #444 $p);
}
Wir registrieren die Variablen --x und --y
CSS.registerProperty({
name: '--x',
syntax: '<length-percentage>',
initialValue: '0%',
inherits: true
});
CSS.registerProperty({
name: '--y',
syntax: '<length-percentage>',
initialValue: '0%',
inherits: true
});
Dann fügen wir die Animationen hinzu
html {
/* same as before */
animation: a 0s ease-in-out -2.3s alternate infinite;
animation-name: x, y;
animation-duration: 4.1s, 2.9s;
}
@keyframes x { to { --x: #{100% - $p} } }
@keyframes y { to { --y: #{100% - $p} } }
Das Ergebnis sehen Sie unten

Wir können diese Technik des Animierens der verschiedenen benutzerdefinierten Eigenschaften, die wir in der Gradientenfunktion verwenden, nutzen, um die Jalousien in unserem ursprünglichen Beispiel anders schließen zu lassen, anstatt zurückzugehen. Dazu führen wir zwei weitere CSS-Variablen ein: --c0 und --c1
$c: #f90 #444;
html {
--c0: #{nth($c, 1)};
--c1: #{nth($c, 2)};
background: linear-gradient(90deg, var(--c0) var(--pos, 0%), var(--c1) 0) 50%/ 5em;
}
Wir registrieren all diese benutzerdefinierten Eigenschaften
CSS.registerProperty({
name: '--pos',
syntax: '<length-percentage>',
initialValue: '0%',
inherits: true
});
CSS.registerProperty({
name: '--c0',
syntax: '<color>',
initialValue: 'red',
inherits: true
});
/* same for --c1 */
Wir verwenden die gleiche Animation wie zuvor für die Position des ersten Stopps --pos und führen zusätzlich zwei steps()-Animationen für die anderen beiden Variablen ein, die ihre Werte jedes Mal umschalten, wenn eine Iteration der ersten animation (die den Wert von --pos ändert) abgeschlossen ist
$t: 1s;
html {
/* same as before */
animation: a 0s infinite;
animation-name: c0, pos, c1;
animation-duration: 2*$t, $t;
animation-timing-function: steps(1), ease-in-out;
}
@keyframes pos { to { --pos: 100%; } }
@keyframes c0 { 50% { --c0: #{nth($c, 2)} } }
@keyframes c1 { 50% { --c1: #{nth($c, 1)} } }
Und wir erhalten folgendes Ergebnis

Wir können dies auch auf einen radial-gradient() anwenden (es ändert sich nichts außer der background-Deklaration)
background: radial-gradient(circle, var(--c0) var(--pos, 0%), var(--c1) 0);

Taktisch gesehen funktioniert das Gleiche auch für conic-gradient()
background: conic-gradient(var(--c0) var(--pos, 0%), var(--c1) 0);

Wiederholte Verläufe sind ebenfalls eine Option, die im radialen Fall einen wellenartigen Effekt erzeugt
$p: 2em;
html {
/* same as before */
background: repeating-radial-gradient(circle,
var(--c0) 0 var(--pos, 0px), var(--c1) 0 $p);
}
@keyframes pos { 90%, 100% { --pos: #{$p} } }

Und ein Helix-/Strahlen-Effekt im konischen Fall
$p: 5%;
html {
/* same as before */
background: repeating-conic-gradient(
var(--c0) 0 var(--pos, 0%), var(--c1) 0 $p);
}
@keyframes pos { 90%, 100% { --pos: #{$p} } }

Wir können eine weitere CSS-Variable hinzufügen, um die Dinge interessanter zu gestalten
$n: 20;
html {
/* same as before */
background: radial-gradient(circle at var(--o, 50% 50%),
var(--c0) var(--pos, 0%), var(--c1) 0);
animation: a 0s infinite;
animation-name: c0, o, pos, c1;
animation-duration: 2*$t, $n*$t, $t;
animation-timing-function: steps(1), steps(1), ease-in-out;
}
@keyframes o {
@for $i from 0 to $n {
#{$i*100%/$n} { --o: #{random(100)*1%} #{random(100)*1%} }
}
}
Wir müssen diese Variable registrieren, damit das Ganze funktioniert
CSS.registerProperty({
name: '--o',
syntax: '<length-percentage>',
initialValue: '50%',
inherits: true
});
Und das ist es! Das Ergebnis sehen Sie unten

Ich würde sagen, die Zukunft des Änderns von Verläufen mit Keyframe-Animationen sieht ziemlich gut aus. Aber in der Zwischenzeit, für browserübergreifende Lösungen, bleibt der JavaScript-Weg der einzig gültige.
Super!!!!
Für einfachere/mehr „deklarative“ JS-basierte Gradientenanimationen habe ich
animate-backgroundsgeschrieben, das es Ihnen ermöglicht, Standard-jQuery- oder anime.js-Animationen zu nutzen und Verläufe wie jede andere CSS-Eigenschaft zu animieren.Hier ist ein browserbasiertes Tool zum Spielen mit dem Anpassen (über Sass-Mixins) und Animieren von Gradientenmustern wie denen in Lea Verous Mustergalerie. Denken Sie an „animiertes kariertes Muster“.