Skip to content

Keyframe Animations

Jank!! Performance, Link abspeichern!

Keyword @keyframes:

@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

Jede keyframe animation braucht einen Namen! Diese Namen funktionieren wie globale Variabe. Wir können überall im CSS darauf zurückgreifen. Daher spielt es auch keine Rolle, an welcher Stelle im CSS sie stehen (vg. hoisting in JavaScript).

Keyframe animations ticken ähnlich wie Funktionen in JavaScript. Wir definieren eine Funktion, aber von alleine tut sie erst einmal gar nichts. In JavaScript müssen wir die Funktion aufrufen, in CSS müssen wir die keyframe animation auf ein bestimmtes Element anwenden. Das machen wir mit der animation Eigenschaft:

.element {
animation: fadeIn 1000ms;
}

Die Eigenschaft benötigt mindestens zwei Werte:

  • den Namen der keyframe animation
  • die Dauer der Animation (angegeben in Millisekunden ms)

Wenn wir die fadeIn Animation anwenden, wird alles, was im from-Block steht, sofort auf das Element angewendet, und geht dann über die Dauer von einer Sekunde auf das CSS im to-Block über.

animation ist eine Shorthand, in Langform würde sie so aussehen:

.element {
animation-name: fadeIn;
animation-duration: 1000ms;
}

Die Shorthand ist aber weitaus gebräuchlicher.

Wir können mehrere Eigenschaften mit einer Animation ändern.

Hello World!
<div class="box">Hello World!</div>
@keyframe fadeIn {
from {
opacity: 0;
background-color: royalblue;
color: white;
}
to {
opacity: 1;
background-color: darkseagreen;
color: black;
}
}
.box {
inline-size: fit-content;
padding: 1.5rem 3rem;
background-color: darkseagreen;
font-weight: bold;
font-size: 1.5rem;
color: black;
animation: fadeIn 2000ms;
}

Keyframe animations laufen immer nur einmal, aber mit dem Keyword infinite können wir sie in einer Schleife abspielen (nützlich z.B. zum laden von Spinnern). Die Langform dazu ist animation-iteration-count.

.element {
animation: animationName 1000ms infinite;
}

Mit from-to animieren wir von einem Status zu anderen. Wenn wir eine feiner abgestufte Animation brauchen, können wir das mit Prozentwerten machen (Animation angehalten!!!)

@keyframes fancySpin {
0% {
transform: rotate(0deg) scale(1);
}
25% {
transform: rotate(180deg) scale(1);
}
50% {
transform: rotate(180deg) scale(1.5);
}
75% {
transform: rotate(0deg) scale(1.5);
}
100% {
transform: rotate(0deg) scale(1);
}
}

Mit verschiedenen Timing-Funktionen können wir das “Feeling” der Animationen kontrollieren:

.element {
animation spin 1000ms infinite linear;
}
.element {
animation spin 1000ms infinite ease-in-out;
}

Ein Blinken (also ein oszillieren zwischen zwei Werten) könnten wir als dreistufige Animation erzeugen (0% - opacity: 0, 50% - opacity: 1, 100% - opacity: 0). Die elegantere Variante ist aber, das Keyword alternate zu verwenden. Dann springt die Animation auch hin und her:

<style>
@keyframes twinkle {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
.element {
animation: twinkle 1000ms infinite alternate ease-in-out;
}

Das Keyword alternate wird von der (Longhand-)Eigenschaft animation-direction verwendet. Sie kann drei verschiedene Werte annehmen:

  • normal (default): die Animation startet bei 0% und läuft bis 100%
  • reverse: die Animation startet bei 100% und läuft zurück zu 0% (wie wenn wir einen Film rückwärts abspielen)
  • alternate: die Animation läuft vor und zurück und wechselt dabei die Richtung

Wir können einem Element mehrere Animationen zuweisen! Das hat den großen Vorteil, dass wir für jeden Keyframe eigene Werte (z.B. Dauer) definieren können. Dem Element weisen wir eine kommagetrennte Liste mit den Namen der Animationen zu.

.element {
animation:
fadeIn 1000ms,
bounce 500ms infinite alternate ease-out;
}

Wenn wir eine fadeOut-Animation machen, also die opacity von 1 nach 0 animieren, dann fadet das Element aus, springt aber dann wieder in seinen Ursprungszustand zurück. Das passiert deswegen, weil opacity nur während der Dauer der Animation angewendet wird. Eine Möglichkeit, dem entgegenzuwirken, wäre, dem Element den Endzustand per CSS mitzugeben, d.h, wenn es ausgefadet wird, sollte es grundsätzlich ein opacity: 0 bekommen. Während die Animation läuft, kommen die Deklarationen innerhalb des Keyframes zur Anwendung und überschreiben die des Elementselektors. Dieser Ansatz funktioniert, ist aber nicht optimal, da die Deklaration opacity: 0 doppelt vergeben werden muss - im Keyframe und im Style des Elements.

Statt sich auf Fallback-Deklarationen zu verlassen, können wir animation-fill-mode verwenden.

Hello World
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.box {
/* Add the "forwards" keyword: */
animation: fadeOut 1000ms forwards;
}

animation-fill-mode: forward (default: none) bedeutet, dass das letzte CSS aus der Keyframe-Animation zur Anwendung kommt, selbst wenn im Element selbst etwas anderes deklariert ist.

Wenn wir mit animation-delay: 1000ms eine Verzögerung einbauen, sehen wir denselben Effekt wie beim fadeIn-Beispiel zuvor: Das Element ist da, und erst wenn die Animation beginnt, wird es aus- und dann langsam wieder eingeblendet. Das ist irgendwie sinnlos, aber hier können wir uns mit dem Keyword backwards behelfen. Das sorgt dafür, ähnlich wie forwards, dass das Element den Wert vom Beginn der Animation annimmt. Das Keyword nimmt also das CSS aus dem from-Block und wendet es auf das Element an, sobald es geladen wird.

Es gibt auch noch both, das in speziellen Fällen sinnvoll sein kann. Dabei werden der erste und der letzte Wert auf das Element angewendet. both sollte aber nicht standardmäßig angewendet werden. Der Nachteil von fill-modes ist nämlich, dass sie alle weiteren Änderungen (z.B. mit JavaScript Element.style.opacity) überschreiben.