JavaScript-Animationen
JavaScript-Animationen mit requestAnimationFrame, Easing-Funktionen, Verkettung, der Web Animations API sowie Performance- und Barrierefreiheitstipps lernen.
JavaScript-Animationen bieten eine dynamische Möglichkeit, die Benutzererfahrung auf Webseiten zu verbessern. Von subtilen Effekten bis hin zu komplexen Bewegungen kann die Beherrschung von JavaScript-Animationen die Interaktivität und visuelle Attraktivität Ihrer Projekte erheblich steigern. Dieser umfassende Leitfaden bietet eine eingehende Erkundung von JavaScript-Animationen, einschließlich grundlegender Konzepte, wesentlicher Techniken und praktischer Beispiele, die Ihnen helfen, kompetent im Erstellen ansprechender Animationen zu werden.
Einführung in JavaScript-Animationen
JavaScript-Animationen manipulieren DOM-Elemente (Document Object Model), um visuelle Effekte zu erzeugen. Sie werden verwendet, um Elemente zu verschieben, zu skalieren und zu verändern – als Reaktion auf Benutzerinteraktionen oder automatisch über Zeit. Wenn Sie die Grundprinzipien und Techniken verstehen, können Sie Animationen erstellen, die sowohl performant als auch visuell ansprechend sind.
Warum JavaScript für Animationen verwenden?
JavaScript-Animationen bieten im Vergleich zu CSS-Animationen mehr Kontrolle und Flexibilität. Sie ermöglichen komplexere Sequenzen und Interaktionen und machen es möglich, hochgradig individualisierte Effekte zu erstellen. JavaScript-Animationen können dynamisch gesteuert werden und sind oft notwendig, wenn Sie auf Benutzereingaben reagieren oder mit anderen JavaScript-Funktionalitäten integrieren müssen.
Als Faustregel gilt:
- Greifen Sie auf CSS (
transition/@keyframes) zurück für einfache, deklarative Zustandsänderungen wie Hover-Effekte, Ein- und Ausblenden und Umschalten. Der Browser optimiert diese auf einem separaten Compositor-Thread, sodass sie tendenziell die performanteste Wahl sind. Siehe CSS-Animationen. - Greifen Sie auf JavaScript zurück, wenn die Animation von Daten, Benutzergesten, Physik oder Logik abhängt, die CSS nicht ausdrücken kann – zum Beispiel dem Mauszeiger folgen, auf dynamische Positionen einrasten oder viele Schritte mit Verzweigungsbedingungen verketten.
Für die einfachste JavaScript-Option bietet die integrierte Web Animations API (weiter unten behandelt) CSS-ähnliche Performance mit imperativem Zugriff, während requestAnimationFrame Ihnen vollständige Frame-für-Frame-Kontrolle gibt, wenn Sie sie benötigen.
Grundkonzepte von JavaScript-Animationen
Bevor Sie in spezifische Techniken eintauchen, ist es wichtig, einige grundlegende Konzepte zu verstehen, die JavaScript-Animationen zugrunde liegen:
- Frames Per Second (FPS): Die Rate, mit der Animationsframes angezeigt werden. Ein höherer FPS-Wert führt zu flüssigeren Animationen.
- Easing-Funktionen: Diese Funktionen steuern die Beschleunigung und Verlangsamung von Animationen und verleihen ihnen natürliche Bewegung.
- Timing-Funktionen: Bestimmen die Dauer und Verzögerung von Animationen.
- Keyframes: Definieren den Anfangs-, End- und Zwischenzustand einer Animation.
requestAnimationFrame vs. setInterval
Bevor requestAnimationFrame existierte, wurden Animationen durch setInterval und setTimeout angetrieben, die alle paar Millisekunden einen Callback ausführten. Dieser Ansatz hat zwei Probleme: Das Intervall ist nicht mit der Bildwiederholrate des Bildschirms synchronisiert (was zu fehlenden oder doppelten Frames führt), und der Timer feuert weiterhin, auch wenn der Tab im Hintergrund ist, was CPU und Akku verschwendet.
requestAnimationFrame(callback) löst beides. Der Browser ruft Ihren callback direkt vor dem nächsten Repaint auf – in der Regel etwa 60 Mal pro Sekunde, passend zur Anzeige – und pausiert automatisch, wenn der Tab ausgeblendet wird. Der Callback erhält ein hochauflösendes timestamp-Argument, mit dem Sie den Fortschritt basierend auf der tatsächlich vergangenen Zeit berechnen, anstatt eine feste Framerate anzunehmen.
// setInterval: fixed timer, not synced to the screen, runs in background tabs
let pos = 0;
const id = setInterval(() => {
pos += 2;
if (pos >= 200) clearInterval(id);
}, 16);
// requestAnimationFrame: synced to repaint, pauses in background tabs
function frame(timestamp) {
// use timestamp to drive the animation
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);Verwenden Sie requestAnimationFrame für alles, was die Visuals in jedem Frame aktualisiert.
Einfaches JavaScript-Animationsbeispiel
Beginnen wir mit einem einfachen Beispiel, bei dem wir ein Quadrat über den Bildschirm animieren.
<!DOCTYPE html>
<html>
<head>
<style>
#square {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
left: 0;
top: 50px;
}
</style>
</head>
<body>
<div id="square"></div>
<script>
const square = document.getElementById('square');
let pos = 0;
function move() {
if (pos < window.innerWidth - 50) {
pos += 2;
square.style.transform = 'translateX(' + pos + 'px)';
requestAnimationFrame(move);
}
}
move();
</script>
</body>
</html>Dieses Beispiel demonstriert eine grundlegende Animation, bei der ein rotes Quadrat von der linken Seite des Bildschirms nach rechts bewegt wird. Die Animation verwendet die Funktion requestAnimationFrame, die eine flüssige Bewegung gewährleistet, indem sie die Animation mit der Bildwiederholrate des Displays synchronisiert. Die Funktion move aktualisiert die Position des Quadrats schrittweise und ruft sich selbst kontinuierlich auf, bis das Quadrat den Rand des Fensters erreicht.
Obwohl JS-Animationen häufige Style-Updates erfordern, sollten Sie transform und opacity bevorzugen, um Layout-Reflows zu vermeiden.
Fortgeschrittene Techniken in JavaScript-Animationen
Easing-Funktionen verwenden
Easing-Funktionen lassen Animationen natürlicher wirken, indem sie die Animationsgeschwindigkeit variieren. Sie erwarten typischerweise einen normalisierten Fortschrittswert zwischen 0 und 1. Hier ist ein Beispiel, das eine Easing-Funktion verwendet, um das Quadrat zu animieren:
<!DOCTYPE html>
<html>
<head>
<style>
#square {
width: 50px;
height: 50px;
background-color: blue;
position: absolute;
left: 0;
top: 50px;
}
</style>
</head>
<body>
<div id="square"></div>
<script>
const square = document.getElementById('square');
let start = null;
const duration = 2000; // Animation duration in milliseconds
function easeOutQuad(t) {
return t * (2 - t);
}
function animate(timestamp) {
if (!start) start = timestamp;
let elapsed = timestamp - start;
let progress = Math.min(elapsed / duration, 1);
let easedProgress = easeOutQuad(progress);
square.style.transform = 'translateX(' + (window.innerWidth - 50) * easedProgress + 'px)';
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
</script>
</body>
</html>Dieses Beispiel verbessert die einfache Animation durch die Integration einer Easing-Funktion namens easeOutQuad. Easing-Funktionen erzeugen natürlicher wirkende Animationen, indem sie die Geschwindigkeit des animierten Elements im Laufe der Zeit anpassen. In diesem Fall bewegt sich das blaue Quadrat von links nach rechts, startet schnell und verlangsamt sich, wenn es das Ende erreicht. Die Animationsdauer ist auf 2000 Millisekunden eingestellt, und die Position des Quadrats wird basierend auf dem Eased-Fortschritt aktualisiert.
Animationen verketten
Das Verketten von Animationen ermöglicht es, mehrere Animationen sequenziell auszuführen. Hier ist ein Beispiel eines Quadrats, das sich zuerst nach rechts und dann nach unten bewegt:
<!DOCTYPE html>
<html>
<head>
<style>
#square {
width: 50px;
height: 50px;
background-color: green;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="square"></div>
<script>
const square = document.getElementById('square');
let xPos = 0;
let yPos = 0;
function moveRight() {
if (xPos < window.innerWidth - 50) {
xPos += 2;
square.style.transform = 'translateX(' + xPos + 'px)';
requestAnimationFrame(moveRight);
} else {
xPos = 0;
yPos = 0; // Explicitly reset yPos before downward phase
square.style.transform = 'translateX(0px)';
requestAnimationFrame(moveDown);
}
}
function moveDown() {
if (yPos < window.innerHeight - 50) {
yPos += 2;
square.style.transform = 'translateY(' + yPos + 'px)';
requestAnimationFrame(moveDown);
} else {
yPos = 0; // Reset for repeated cycles
requestAnimationFrame(moveRight);
}
}
moveRight();
</script>
</body>
</html>Dieses Beispiel demonstriert das Verketten von Animationen, indem ein grünes Quadrat zunächst nach rechts und dann nach unten bewegt wird. Die Funktion moveRight bewegt das Quadrat nach rechts, bis es den Rand des Fensters erreicht. Sobald es den rechten Rand erreicht, wird yPos explizit auf 0 zurückgesetzt, bevor moveDown aufgerufen wird. Diese sequentielle Ausführung, kombiniert mit ordnungsgemäßem Zustandsmanagement für wiederholte Zyklen, zeigt, wie man komplexere Animationssequenzen durch das Verketten mehrerer Animationen erstellt.
Mehrere Eigenschaften animieren
Das gleichzeitige Animieren mehrerer Eigenschaften kann komplexere und visuell ansprechendere Effekte erzeugen. Hier ist ein Beispiel, das sowohl Position als auch Farbe ändert:
<!DOCTYPE html>
<html>
<head>
<style>
#square {
width: 50px;
height: 50px;
background-color: purple;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id="square"></div>
<script>
const square = document.getElementById('square');
let pos = 0;
function changeColor(progress) {
let red = Math.floor(255 * progress);
let green = Math.floor(255 * (1 - progress));
return `rgb(${red}, ${green}, 0)`;
}
function animate() {
if (pos < window.innerWidth - 50) {
pos += 2;
let progress = pos / (window.innerWidth - 50);
square.style.transform = 'translateX(' + pos + 'px)';
square.style.backgroundColor = changeColor(progress);
requestAnimationFrame(animate);
}
}
animate();
</script>
</body>
</html>Dieses Beispiel animiert sowohl die Position als auch die Hintergrundfarbe eines lila Quadrats. Während sich das Quadrat von links nach rechts bewegt, wechselt seine Farbe von Rot zu Grün. Die Funktion changeColor berechnet die Farbe basierend auf dem Animationsfortschritt und erzeugt dabei einen Gradienteneffekt. Dies demonstriert, wie mehrere Eigenschaften gleichzeitig animiert werden können, was Komplexität und visuelle Attraktivität zu Animationen hinzufügt.
Die Web Animations API
Ein requestAnimationFrame-Loop manuell zu schreiben gibt Ihnen totale Kontrolle, aber für die meisten zeitlinienbasierten Animationen hat der Browser bereits eine integrierte Engine: die Web Animations API (WAAPI). Der Aufruf von element.animate(keyframes, options) führt die Animation nach Möglichkeit abseits des Haupt-Threads aus (genau wie CSS), sodass Sie flüssige Wiedergabe erhalten, ohne selbst einen Frame-Loop schreiben zu müssen. Es wird auch ein Animation-Objekt zurückgegeben, das Sie pausieren, umkehren, anspringen oder abwarten können.
<!DOCTYPE html>
<html>
<head>
<style>
#box {
width: 50px;
height: 50px;
background-color: teal;
position: absolute;
left: 0;
top: 50px;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById('box');
const animation = box.animate(
[
{ transform: 'translateX(0)', opacity: 1 },
{ transform: 'translateX(300px)', opacity: 0.3 }
],
{
duration: 2000,
easing: 'ease-out',
fill: 'forwards'
}
);
// The returned object gives you imperative control:
animation.finished.then(() => console.log('done'));
// animation.pause(); animation.reverse(); animation.currentTime = 1000;
</script>
</body>
</html>Das erste Argument ist ein array von Keyframes (jeweils ein object aus CSS-Eigenschaften); das zweite setzt duration, easing und Verhaltensweisen wie fill (Endzustand beibehalten), iterations, direction und delay. Da easing dieselben cubic-bezier()- und Schlüsselwortwerte wie CSS akzeptiert, müssen Sie Easing-Mathematik oft gar nicht von Hand schreiben.
Bevorzugen Sie WAAPI, wenn Ihre Animation eine feste Zeitlinie von Eigenschaftsänderungen ist. Reservieren Sie einen manuellen requestAnimationFrame-Loop für Fälle, in denen jeder Frame von Live-Eingaben oder berechnetem Zustand abhängt – wie Physik, Ziehen oder Werte, die nicht im Voraus bekannt sind.
Animationen stoppen und umkehren
Ein requestAnimationFrame-Loop läuft weiter, bis Sie aufhören, neue Frames zu planen. Um einen sofort abzubrechen, speichern Sie die ID, die requestAnimationFrame zurückgibt, und übergeben Sie sie an cancelAnimationFrame:
let rafId;
function loop(timestamp) {
// ...update visuals...
rafId = requestAnimationFrame(loop);
}
rafId = requestAnimationFrame(loop);
// Later, e.g. on a button click or when the element is removed:
cancelAnimationFrame(rafId);Brechen Sie laufende Animationen immer ab, bevor Sie ihre Elemente aus dem DOM entfernen, andernfalls mutiert der Loop weiterhin einen abgetrennten Knoten und verursacht in jedem Frame unnötigen Aufwand. Mit der Web Animations API lauten die Entsprechungen einfach animation.cancel(), animation.pause() und animation.reverse().
Barrierefreiheit: Reduzierte Bewegung respektieren
Starke oder schnelle Bewegungen können bei manchen Benutzern Übelkeit, Schwindel oder Migräne auslösen. Betriebssysteme bieten eine Einstellung zur Reduzierung von Bewegungen an, und Sie sollten diese berücksichtigen. In JavaScript lesen Sie sie mit matchMedia aus und deaktivieren entweder die Animation oder springen direkt zum Endzustand:
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
if (prefersReducedMotion) {
// Skip the animation: apply the final state instantly
square.style.transform = 'translateX(300px)';
} else {
requestAnimationFrame(animate);
}Diese einzelne Prüfung macht Ihre Interfaces sowohl inklusiver als auch angenehmer für Benutzer, die auf Bewegung verzichten möchten.
Performance-Optimierung für JavaScript-Animationen
Um flüssige und effiziente Animationen zu gewährleisten, befolgen Sie diese Performance-Optimierungstipps:
requestAnimationFrameverwenden: Diese Methode synchronisiert mit der Display-Bildwiederholrate und liefert flüssigere Animationen.- DOM-Manipulationen minimieren: Bündeln Sie DOM-Updates, um Reflows und Repaints zu reduzieren. Bevorzugen Sie
transformundopacityfür Positionsänderungen, um GPU-Beschleunigung zu nutzen. - CSS optimieren: Verwenden Sie GPU-beschleunigte CSS-Eigenschaften wie
transformundopacity. - Events drosseln: Begrenzen Sie die Häufigkeit von Events wie
resizeoderscrollmithilfe von Throttling- oder Debouncing-Techniken. - Animationen ordnungsgemäß stoppen: Verwenden Sie
cancelAnimationFrame, um Animationen zu stoppen, wenn sie nicht mehr benötigt werden. Speichern Sie die Animations-ID und rufen SiecancelAnimationFrame(id)auf, um Speicherlecks zu vermeiden. Beispiel:let animationId = requestAnimationFrame(animate); // ... later ... cancelAnimationFrame(animationId); - Layout Thrashing vermeiden: Lesen Sie keine Layout-Eigenschaften (z. B.
offsetWidth,getBoundingClientRect) innerhalb des Animations-Loops, da dies den Browser zwingt, Styles mitten im Frame neu zu berechnen, was zu Ruckeln führen kann.
Sie können Animationen auch ausschließlich mit CSS erstellen (ohne JavaScript), was in der Regel zu besserer Performance führt. Siehe CSS-Animationen.
Fazit
Die Beherrschung von JavaScript-Animationen erfordert das Verstehen grundlegender Prinzipien, die Implementierung fortgeschrittener Techniken und die Optimierung der Performance. Indem Sie diesem Leitfaden folgen, können Sie ansprechende und reaktionsfähige Animationen erstellen, die die Benutzererfahrung verbessern. Experimentieren Sie mit verschiedenen Easing-Funktionen, Verkettungen und Eigenschaftsanimationen, um das volle Potenzial von JavaScript in Ihren Webprojekten zu entfalten.
Um weiterzugehen, erkunden Sie diese verwandten Themen:
- CSS-Animationen — die deklarative, oft performantere Alternative.
- Scheduling: setTimeout und setInterval — Timer-basierte Planung und warum
requestAnimationFramefür visuelle Elemente bevorzugt wird. - Einführung in Browser-Events — Animationen als Reaktion auf Benutzerinteraktionen auslösen.
- JavaScript HTML DOM — Elemente auswählen und manipulieren, die Sie animieren.