Federartige Easing-Funktionen bauen: linear() statt Spring-Bibliotheken
AI generated
{ }
@
CSS · Easing · linear() · Spring-Animation
Federartige Easing-Funktionen bauen
linear() statt Spring-Bibliotheken

Echte Feder-Physik in Animationen war lange Domäne von JavaScript-Bibliotheken wie Framer Motion oder React Spring. Die CSS-Funktion linear() erlaubt jetzt, beliebig komplexe Easing-Kurven, inklusive Overshoot und Bounce, direkt als Stützpunkt-Liste im Stylesheet zu definieren, ganz ohne Laufzeit-JavaScript.

16 Min. Lesezeit linear() · Custom Properties · Overshoot · Damping Chrome 113+ · Firefox 112+ · Safari 17.2+

1. Warum CSS bisher keine echten Federn kannte

Klassische CSS-Timing-Funktionen wie ease, ease-in-out oder selbst cubic-bezier() beschreiben ausschließlich monotone Kurven zwischen zwei Werten: die Geschwindigkeit ändert sich, die Richtung aber nie. Eine echte Feder-Bewegung dagegen schwingt über ihr Ziel hinaus und pendelt sich erst nach mehreren Oszillationen ein, ein Verhalten, das mit einem einzelnen Bézier-Polynom mathematisch nicht abbildbar ist. Genau deshalb griffen Entwickler für federartige Easing-Effekte bisher fast ausschließlich zu JavaScript-Bibliotheken, die die Physik einer gedämpften Feder pro Frame neu berechnen.

Diese JavaScript-Lösungen funktionieren zuverlässig, kosten aber etwas, das reines CSS nicht kostet: Hauptthread-Zeit bei jedem einzelnen Animationsframe, zusätzliches Bundle-Gewicht durch die Bibliothek selbst, und eine Abhängigkeit von der Ausführung des JavaScript-Codes, die bei langsamen Geräten oder blockiertem Main-Thread ins Stocken geraten kann. Eine federartige Easing-Funktion, die komplett in CSS lebt, umgeht all diese Probleme, weil der Browser die Animation auf dem Compositor-Thread abspielen kann.

Mit der CSS-Funktion linear() ist genau das jetzt möglich. Statt einer glatten mathematischen Formel beschreibt linear() eine Folge von Stützpunkten, zwischen denen linear interpoliert wird. Mit genügend Stützpunkten lässt sich jede beliebige Kurve annähern, einschließlich einer Kurve, die über 100 Prozent hinausschießt und zurückschwingt, exakt das Verhalten einer physikalischen Feder.

2. Die linear() Funktion verstehen: Stützpunkte statt Kurve

Die Syntax von linear() ist bewusst simpel: eine kommagetrennte Liste von Zahlen, optional mit Prozentangabe der Position auf der Zeitachse. linear(0, 0.5 50%, 1) etwa definiert drei Stützpunkte: bei 0 Prozent Zeit steht der Fortschritt bei 0, bei 50 Prozent Zeit bei 0.5, bei 100 Prozent Zeit bei 1. Zwischen den Stützpunkten interpoliert der Browser linear, was bei wenigen Punkten kantig wirkt, bei vielen Punkten aber praktisch nicht mehr von einer glatten Kurve zu unterscheiden ist.

Der entscheidende Unterschied zu cubic-bezier(): die Werte in linear() müssen nicht zwischen 0 und 1 liegen. Ein Wert von 1.1 bedeutet, dass die Animation an dieser Stelle 110 Prozent ihres Zielwerts erreicht, bevor sie wieder zurückschwingt. Diese Fähigkeit, den Zielwert kurzzeitig zu überschreiten und wieder zurückzukehren, ist die Grundlage jeder federartigen Easing-Kurve in reinem CSS.


/* Basic linear() syntax: comma-separated stops, optional position */
.simple-ease {
  transition-timing-function: linear(0, 0.25, 0.75, 1);
}

/* Explicit position: value at a specific percentage of the duration */
.overshoot-preview {
  transition-timing-function: linear(
    0,
    0.6 25%,
    1.08 55%,   /* overshoots past the target value */
    0.98 75%,
    1
  );
}

Für ein einfaches Overshoot-Gefühl reichen bereits fünf bis sieben Stützpunkte aus. Für eine überzeugende, mehrfach oszillierende Federanimation mit sichtbarem Ausschwingen sind allerdings zwanzig bis vierzig Stützpunkte üblich, die man realistischerweise nicht mehr von Hand tippt, sondern aus einer physikalischen Formel generiert.

3. Eine Feder-Funktion mathematisch generieren

Die Physik einer gedämpften Feder lässt sich mit drei Parametern beschreiben: der Steifigkeit (stiffness), der Dämpfung (damping) und der Masse (mass) des bewegten Objekts. Die Standard-Formel für die Position einer gedämpften harmonischen Schwingung zur Zeit t lautet vereinfacht 1 - e^(-ζωt) · cos(ωd·t), wobei ζ den Dämpfungsgrad und ωd die gedämpfte Kreisfrequenz beschreibt. Diese Formel wird an vielen diskreten Zeitpunkten ausgewertet, jeder Wert wird zu einem Stützpunkt in der linear()-Liste.

In der Praxis schreibt man dafür ein kleines Skript, das für eine gewünschte Kombination aus Steifigkeit und Dämpfung eine feste Anzahl von Stützpunkten berechnet und als fertige linear()-Deklaration ausgibt. Dieses Skript muss nicht im Produktionscode laufen, es ist reines Build-Time-Tooling: das Ergebnis ist eine statische CSS-Zeile, die exakt dieselbe visuelle Kurve erzeugt wie eine JavaScript-Spring-Bibliothek zur Laufzeit, aber ohne jede Laufzeitkosten.


// Build-time script: generate a linear() easing string from spring physics
function springToLinear(stiffness = 300, damping = 20, mass = 1, steps = 30) {
  const w0 = Math.sqrt(stiffness / mass);
  const zeta = damping / (2 * Math.sqrt(stiffness * mass));
  const wd = w0 * Math.sqrt(1 - zeta * zeta);

  const points = [];
  for (let i = 0; i <= steps; i++) {
    const t = i / steps;
    const decay = Math.exp(-zeta * w0 * t * 4); // scaled duration window
    const value = 1 - decay * Math.cos(wd * t * 4);
    points.push(value.toFixed(4));
  }
  return `linear(${points.join(', ')})`;
}

console.log(springToLinear(300, 20, 1, 24));
// linear(0, 0.1834, 0.4412, ..., 1.0812, ..., 0.9987, 1)

Diese generierte Zeichenkette wird einmalig in das Stylesheet kopiert und bleibt danach statisch. Ändert sich der gewünschte Feder-Charakter, etwa weniger Dämpfung für ein verspielteres Überschwingen, wird das Skript einmal neu ausgeführt und die neue Zeichenkette ersetzt die alte. Das ist derselbe Workflow wie bei generierten Sprite-Sheets oder komprimierten Assets: Generierung zur Build-Zeit, statisches Ergebnis zur Laufzeit.

4. Overshoot und Bounce mit linear() nachbilden

Nicht jede federartige Easing-Kurve muss aus einer vollständigen physikalischen Simulation stammen. Für viele UI-Zwecke reicht eine handgebaute Annäherung mit wenigen charakteristischen Stützpunkten, die den Eindruck einer Feder erzeugen, ohne den mathematischen Anspruch einer exakten Simulation zu erheben. Ein typisches Muster: schneller Anstieg, leichtes Überschwingen über den Zielwert, kurzes Zurückfedern, dann Einpendeln.

Für einen Bounce-Effekt, bei dem ein Element wie ein Ball mehrfach auf einer Fläche aufkommt, eignen sich mehrere aufeinanderfolgende Überschwinger mit abnehmender Amplitude. Diese Muster lassen sich als wiederverwendbare Rezepte katalogisieren: ein sanfter Spring für Tooltips, ein energischer Bounce für Erfolgsmeldungen, ein fast unmerklicher Overshoot für Hover-Zustände.


/* Gentle spring: subtle overshoot, good for tooltips and popovers */
:root {
  --ease-spring-soft: linear(0, 0.52 30%, 0.98 55%, 1.02 70%, 1);
}

/* Energetic bounce: multiple decaying overshoots, good for success states */
:root {
  --ease-spring-bounce: linear(
    0, 0.35 15%, 0.72 30%, 1.06 45%,
    0.92 58%, 1.03 68%, 0.98 78%, 1.01 88%, 1
  );
}

.toast-enter {
  animation: toast-in 0.5s var(--ease-spring-bounce) both;
}
@keyframes toast-in {
  from { transform: translateY(-40px) scale(0.9); opacity: 0; }
}

Wichtig für glaubwürdige Federanimationen ist die Amplitude des Überschwingens: mehr als etwa acht bis zwölf Prozent über dem Zielwert wirkt schnell übertrieben und lenkt vom eigentlichen Inhalt ab. Für Mikro-Interaktionen wie Button-Klicks oder kleine Statuswechsel sind zwei bis fünf Prozent Überschwingen meist die überzeugendere Wahl, für auffälligere Elemente wie Modal-Dialoge oder Erfolgsmeldungen darf es etwas mehr sein.

5. Werkzeuge zur Erzeugung von linear()-Werten

Da niemand vierzig Stützpunkte von Hand berechnen möchte, haben sich mehrere webbasierte Generatoren etabliert, die eine Feder anhand von Steifigkeit, Dämpfung und Masse simulieren und die fertige linear()-Zeichenkette per Klick ausgeben, oft direkt mit einer Live-Vorschau der resultierenden Bewegung. Diese Werkzeuge übernehmen exakt die Rolle des im vorigen Abschnitt gezeigten Build-Skripts, nur mit grafischer Oberfläche statt Code.

Für Teams, die konsistente Federanimationen über viele Komponenten hinweg brauchen, lohnt sich trotzdem ein eigenes kleines Node-Skript im Repository, das exakt dieselbe Formel wie die Web-Tools verwendet, aber in die eigene Design-Token-Pipeline eingebunden ist. So bleiben Spring-Parameter versioniert und nachvollziehbar, statt in einer externen Web-App verborgen zu sein, deren Ergebnis nur als Copy-Paste-Text im Projekt landet.

6. Spring-Easings als Custom Properties wiederverwendbar machen

Eine generierte linear()-Zeichenkette ist lang und unhandlich, wenn sie in jeder einzelnen Regel wiederholt werden muss. Der saubere Weg ist, jede fertige federartige Easing-Kurve einmal als CSS-Custom-Property auf :root zu deklarieren und danach überall im Stylesheet per var() zu referenzieren, exakt wie ein Farbwert oder ein Spacing-Token.

Diese Herangehensweise macht Spring-Easings zu einem echten Design-Token: --ease-spring-soft, --ease-spring-bounce, --ease-spring-snappy und Ähnliches lassen sich zentral pflegen, in Dokumentation beschreiben und bei Bedarf projektweit austauschen, ohne dass jede einzelne Komponente angefasst werden müsste. Wird die Design-Sprache angepasst, ändert sich nur der Wert der Custom Property.


:root {
  /* Named spring tokens — generated once, reused everywhere */
  --ease-spring-snappy: linear(0, 0.62 22%, 1.05 42%, 0.99 60%, 1);
  --ease-spring-soft: linear(0, 0.52 30%, 0.98 55%, 1.02 70%, 1);
}

.button {
  transition: transform 0.3s var(--ease-spring-snappy);
}
.button:active {
  transform: scale(0.96);
}

.modal-panel {
  animation: modal-in 0.4s var(--ease-spring-soft) both;
}

7. Performance-Vergleich: linear() gegen JavaScript-Spring-Bibliotheken

Der Performance-Vorteil einer linear()-basierten Federanimation gegenüber einer JavaScript-Spring-Bibliothek liegt vor allem in der Ausführungsumgebung. Eine CSS-Animation mit linear()-Timing wird, sofern nur transform und opacity animiert werden, vollständig auf dem Compositor-Thread berechnet. Der Main-Thread bleibt frei für andere Aufgaben, selbst wenn er durch aufwendiges JavaScript blockiert ist, läuft die Animation weiter sichtbar flüssig.

Eine JavaScript-Spring-Bibliothek dagegen berechnet die Feder-Physik typischerweise pro requestAnimationFrame-Callback auf dem Main-Thread neu und schreibt das Ergebnis in Inline-Styles. Ist der Main-Thread durch andere Aufgaben belastet, etwa durch das Parsen einer großen JSON-Antwort, gerät die Animation ins Stocken. Für Bundle-Größe gilt derselbe Vorteil: eine linear()-Kurve kostet null zusätzliches JavaScript-Gewicht, während gängige Spring-Bibliotheken mehrere Kilobyte zur gezippten Bundle-Größe beitragen.

8. Grenzen von linear() und wann JavaScript nötig bleibt

So mächtig linear() für statische, vorab berechnete Kurven ist, für interaktive, physikbasierte Animationen mit laufend wechselnden Zielwerten stößt die Technik an ihre Grenzen. Ein Drag-Interaktion, bei der der Nutzer ein Element zieht und beim Loslassen eine Feder-Bewegung zum nächsten Rastpunkt einsetzen soll, kennt den exakten Zielwert erst zur Laufzeit. Eine vorab berechnete linear()-Kurve kann diesen dynamischen Zielwert nicht berücksichtigen, weil sie eine feste Sequenz von Stützpunkten für eine feste Distanz darstellt.

Für solche Fälle mit variabler Zieldistanz zur Laufzeit bleibt eine JavaScript-Spring-Bibliothek die richtige Wahl, weil sie die Physik bei jedem Frame neu mit dem aktuellen Zielwert berechnet. Ein sinnvoller Kompromiss in vielen Projekten: linear() für alle vorhersehbaren UI-Übergänge wie Modals, Toasts und Hover-Zustände nutzen, JavaScript-Springs nur dort einsetzen, wo tatsächlich Nutzerinteraktion in Echtzeit die Zieldistanz bestimmt.

9. Easing-Funktionen im Vergleich

Für die Entscheidung zwischen den verfügbaren Easing-Techniken hilft ein direkter Vergleich der wichtigsten Eigenschaften, von der klassischen Bézier-Kurve bis zur vollständig physikalisch generierten Feder.

Technik Überschwingen möglich Laufzeitkosten Dynamische Zieldistanz
cubic-bezier() Nein Keine Nicht relevant
linear() Spring Ja Keine (Compositor) Nein
JavaScript-Spring-Bibliothek Ja Main-Thread pro Frame Ja
steps() Nein Keine Nicht relevant

Für die überwiegende Mehrheit der UI-Übergänge mit bekannter, fester Distanz ist linear() die überlegene Wahl: null Bundle-Gewicht, keine Main-Thread-Kosten, dieselbe visuelle Qualität wie eine Spring-Bibliothek. Nur bei echtzeit-interaktiven Drag-Gesten mit variabler Zieldistanz bleibt JavaScript unverzichtbar.

Mironsoft

Feingranulare Micro-Interaktionen und Animations-Design-Systeme

Animationen, die sich lebendig statt mechanisch anfühlen?

Wir entwickeln eigene linear()-basierte Spring-Easings für euer Design-System, inklusive Build-Tooling zur Generierung und Dokumentation als wiederverwendbare Custom Properties.

Analyse

Bestehende Animationen auf Konsistenz und Overshoot-Verhalten prüfen

Umsetzung

Spring-Token-Set generieren und als Custom Properties einbinden

Performance

Compositor-Thread-Check und Vergleich gegen bestehende JS-Bibliotheken

10. Zusammenfassung

Die CSS-Funktion linear() macht echte federartige Easing-Kurven ohne jede JavaScript-Bibliothek möglich. Anders als cubic-bezier() erlaubt sie Werte über 100 Prozent hinaus und damit ein Überschwingen über den Zielwert, das Kernmerkmal jeder Feder-Bewegung. Kurven mit wenigen Stützpunkten reichen für ein leichtes Overshoot-Gefühl, physikalisch generierte Kurven mit zwanzig bis vierzig Stützpunkten liefern mehrfach oszillierende, überzeugende Federanimationen.

Die generierten linear()-Werte werden am besten als benannte Custom Properties gepflegt, damit Spring-Easings zum echten Design-Token werden, statt in jeder Regel dupliziert zu sein. Der Performance-Vorteil gegenüber JavaScript-Spring-Bibliotheken ist erheblich: keine Main-Thread-Kosten, keine zusätzliche Bundle-Größe, dieselbe visuelle Qualität. Nur bei dynamischer Zieldistanz zur Laufzeit, etwa bei Drag-Interaktionen, bleibt eine JavaScript-Lösung die richtige Wahl.

Federartige Easing-Funktionen bauen — Das Wichtigste auf einen Blick

linear() Grundlage

Werte über 1 erzeugen Überschwingen, das mit cubic-bezier() nicht möglich ist.

Generierung

Feder-Physik einmalig zur Build-Zeit berechnen, statische linear()-Zeichenkette ins CSS kopieren.

Design-Tokens

Spring-Kurven als Custom Properties auf :root pflegen, zentral austauschbar.

Grenzen

Bei dynamischer Zieldistanz zur Laufzeit bleibt eine JavaScript-Spring-Bibliothek nötig.

11. FAQ: Federartige Easing-Funktionen bauen

1Was macht linear() anders als cubic-bezier()?
Stützpunkt-Liste statt Formel, mit Werten über 1 für Überschwingen, was cubic-bezier() nicht abbilden kann.
2Wie viele Stützpunkte sind nötig?
Fünf bis sieben für leichtes Overshoot, zwanzig bis vierzig für eine mehrfach oszillierende Feder.
3Wie generiere ich die Stützpunkte?
Mit einem Build-Skript, das die Formel der gedämpften Schwingung auswertet und als linear()-Liste ausgibt.
4Kostet linear() Performance?
Nein, bei transform und opacity läuft alles auf dem Compositor-Thread, unabhängig vom Main-Thread.
5Wie viel Überschwingen ist angemessen?
Zwei bis fünf Prozent für Mikro-Interaktionen, bis zwölf Prozent für auffälligere Elemente.
6Als Custom Property speichern?
Ja, das macht Spring-Easings zum wiederverwendbaren Design-Token ohne Duplikation.
7Ersetzt linear() JavaScript-Springs?
Bei fester Distanz ja, bei dynamischer Zieldistanz zur Laufzeit bleibt JavaScript nötig.
8Browser-Unterstützung?
Chrome und Edge ab 113, Firefox ab 112, Safari ab 17.2. Fallback mit cubic-bezier() empfohlen.
9Bounce mit mehreren Aufprallen?
Mehrere Überschwinger mit abnehmender Amplitude als Stützpunkte definieren.
10Wo mehrere Varianten speichern?
Als benannte Custom Properties auf :root, dokumentiert im Design-System des Projekts.