Als das W3C im September 2001 die erste Empfehlung für SVG veröffentlichte, war Bewegung bereits Teil der Spezifikation. Elemente wie animate, animateTransform und animateMotion erlaubten es, Farben zu verändern, Formen zu drehen und Objekte entlang eines Pfades wandern zu lassen, ganz ohne Skript und zu einer Zeit, in der animierte Webgrafik in aller Regel Flash bedeutete. Die Animation gehört also zur Grundausstattung des Formats.
Für die SVG-Animation stehen heute mehrere Wege offen: die alten SMIL-Elemente, CSS-Transitions und Keyframes, die Web Animations API und darüber eine Reihe von Bibliotheken. Welcher davon passt, entscheidet sich weniger an der Technik als an der Frage, was eine Animation leisten soll. Ein Ladeindikator stellt andere Anforderungen als ein Menü-Icon, das auf einen Klick reagiert, und beide haben wenig gemein mit einem Diagramm, dessen Linie sich beim Scrollen zeichnet. Fast alle diese Wege setzen voraus, dass die Grafik inline im HTML steht oder auf anderem Weg als Struktur erreichbar ist.
Die Animationselemente aus der Frühzeit stammen aus SMIL, der Synchronized Multimedia Integration Language, und sie funktionieren bis heute. Ein Ladeindikator lässt sich damit vollständig in der Grafik selbst beschreiben, ohne eine Zeile CSS oder JavaScript:
<svg viewBox="0 0 24 24" width="48" height="48" aria-hidden="true">
<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-dasharray="42 100">
<animateTransform attributeName="transform" type="rotate"
from="0 12 12" to="360 12 12"
dur="1s" repeatCount="indefinite" />
</circle>
</svg>
2015 kündigte das Chromium-Team an, SMIL aus Chrome zu entfernen, und empfahl stattdessen CSS und die Web Animations API. Nach deutlichem Widerspruch aus der Entwicklergemeinde wurde die Ankündigung wieder zurückgezogen. Seitdem führt SMIL ein etwas randständiges, aber stabiles Dasein: Alle aktuellen Browser beherrschen es, und für bestimmte Aufgaben ist es nach wie vor die eleganteste Lösung.
Der eigentliche Vorzug liegt in der Kapselung. Weil die Animation in der Datei selbst steckt, läuft sie auch dann, wenn die Grafik per img eingebunden wird. Das gilt übrigens ebenso für CSS-Keyframes, die in einem style-Block innerhalb der SVG-Datei stehen. Was bei dieser Einbindung verloren geht, ist alles, was von außen kommt: Hover-Zustände aus dem Stylesheet der Seite, Steuerung per Skript und, wie sich weiter unten zeigt, die Rücksicht auf Menschen, die Bewegung lieber abschalten.
Sobald eine SVG inline im Dokument steht, sind ihre Elemente gewöhnliche Knoten im DOM. fill, stroke, opacity und transform lassen sich mit Transitions weich verändern, gesteuert über Hover, Fokus oder ARIA-Zustände. Ein klassisches Beispiel ist das Menü-Icon, dessen drei Striche sich beim Öffnen zu einem Kreuz verschränken:
<button class="menu-toggle" aria-expanded="false" aria-controls="hauptmenue">
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<rect class="bar bar--top" x="3" y="5" width="18" height="2" rx="1" />
<rect class="bar bar--middle" x="3" y="11" width="18" height="2" rx="1" />
<rect class="bar bar--bottom" x="3" y="17" width="18" height="2" rx="1" />
</svg>
<span class="visually-hidden">Menü</span>
</button>
.menu-toggle .bar {
fill: currentColor;
transform-box: fill-box;
transform-origin: center;
transition: transform .25s ease, opacity .2s ease;
}
.menu-toggle[aria-expanded="true"] .bar--top { transform: translateY(6px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] .bar--middle { opacity: 0; }
.menu-toggle[aria-expanded="true"] .bar--bottom { transform: translateY(-6px) rotate(-45deg); }
Die unscheinbarste Zeile ist zugleich die wichtigste. Ohne transform-box: fill-box bezieht sich der Drehpunkt eines SVG-Elements auf den Ursprung des gesamten Koordinatensystems, also auf die linke obere Ecke der Zeichenfläche. Die Striche rotieren dann um einen Punkt weit außerhalb ihrer selbst und fliegen aus dem Bild. Kaum ein Detail sorgt beim Animieren von SVG für so viel Ratlosigkeit, und kaum eines ist so schnell behoben.
Bemerkenswert ist auch, woran die Animation hängt. Sie reagiert auf aria-expanded, also auf denselben Zustand, den ein Screenreader ausliest. Das Skript, das den Button umschaltet, muss sich um die Optik nicht kümmern, und die Bewegung kann nie etwas anderes behaupten als die Semantik des Elements.
Der wohl bekannteste Effekt der SVG-Animation ist das Line Drawing: Ein Pfad erscheint, als würde er in diesem Moment von einer unsichtbaren Hand gezogen. Dahinter steckt ein Trick mit der Strichelung. stroke-dasharray definiert einen einzigen Strich, der genau so lang ist wie der Pfad, stroke-dashoffset schiebt ihn um dieselbe Länge aus dem Sichtfeld, und die Animation holt ihn zurück. Früher musste die Länge des Pfades per getTotalLength() ermittelt werden. Das Attribut pathLength erspart diesen Schritt, weil es die Länge schlicht auf einen frei gewählten Wert normiert:
<svg class="signet" viewBox="0 0 120 40" aria-hidden="true">
<path pathLength="1" d="M5 30 C 30 5, 60 5, 115 30" />
</svg>
.signet path {
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: zeichnen 1.2s ease-out forwards;
}
@keyframes zeichnen {
to { stroke-dashoffset: 0; }
}
Das funktioniert für Signets und Unterschriften ebenso wie für Diagrammlinien oder das Häkchen nach einem abgeschickten Formular. Die Einschränkung liegt in der Natur der Sache: Gezeichnet werden können nur Konturen. Ein Logo, das aus gefüllten Flächen besteht, muss für diesen Effekt eigens mit Strichpfaden nachgezeichnet werden, und das ist Gestaltungsarbeit, die sich mit keiner CSS-Eigenschaft abkürzen lässt.
CSS beschreibt Zustände und die Übergänge zwischen ihnen. Sobald eine Animation von Daten abhängt, von der Scrollposition, von einer Abfolge mehrerer Schritte oder davon, dass sie angehalten, umgekehrt oder an einer bestimmten Stelle fortgesetzt werden soll, braucht es JavaScript. Die Web Animations API ist dafür die native Brücke: Sie nutzt dieselbe Engine wie CSS-Animationen, liefert aber ein Objekt zurück, das sich mit play(), pause(), reverse() und finish() steuern lässt. Kombiniert mit einem IntersectionObserver zeichnet sich eine Diagrammlinie erst, wenn sie tatsächlich ins Bild kommt:
const linie = document.querySelector('.chart-line');
const animation = linie.animate(
[{ strokeDashoffset: 1 }, { strokeDashoffset: 0 }],
{ duration: 900, easing: 'ease-out', fill: 'forwards' }
);
animation.pause();
new IntersectionObserver(([eintrag], beobachter) => {
if (eintrag.isIntersecting) {
animation.play();
beobachter.disconnect();
}
}).observe(linie);
Eine Sonderstellung nimmt das Morphing ein, also die fließende Verwandlung einer Form in eine andere. Technisch wird dabei das d-Attribut eines Pfades animiert, und das setzt voraus, dass Ausgangs- und Zielpfad kompatibel sind: gleiche Anzahl und gleiche Art von Pfadbefehlen, sonst springt die Form, statt zu fließen. Für die Umsetzung gibt es mehrere Wege. SMIL kann d animieren, einige Browser erlauben es auch per CSS über die Eigenschaft d: path(), allerdings nicht einheitlich, und für alles, was darüber hinausgeht, sind Bibliotheken zuständig, die unterschiedliche Pfade vorab angleichen.
Unter diesen Bibliotheken ist GSAP die bekannteste. Seit 2025 ist sie vollständig kostenfrei nutzbar, einschließlich der früher kostenpflichtigen Plugins für Morphing und Line Drawing. Für komplexe Zeitleisten mit vielen synchronisierten Elementen ist sie ein ausgesprochen komfortables Werkzeug. Wer Animationen aus After Effects übernehmen will, greift eher zu Lottie, das die exportierten Daten als JSON-Datei ausliefert und im Browser als SVG rendert. Beides hat Gewicht im Bundle, und für einen Hover-Effekt an einem Icon wäre es ungefähr so angemessen, einen Umzugswagen für eine Postkarte zu bestellen.
Bei HTML-Elementen gelten transform und opacity als günstig, weil der Browser sie an den Compositor übergeben kann, ohne die Seite bei jedem Frame neu zu zeichnen. Innerhalb einer SVG ist diese Rechnung weniger verlässlich. Je nach Browser und Konstellation wird die Grafik bei jeder Veränderung eines inneren Elements neu gerastert, und das fällt umso stärker ins Gewicht, je mehr Knotenpunkte ihre Pfade haben. Besonders teuer sind animierte Filter: Ein feGaussianBlur, dessen Stärke sich über eine Sekunde verändert, kann ein schwächeres Gerät spürbar ins Stocken bringen.
Daraus ergeben sich ein paar praktische Regeln. Wo es genügt, die gesamte Grafik zu bewegen, sollte die Animation am äußeren svg-Element ansetzen statt an jedem Pfad einzeln. Exportierte Dateien lassen sich mit Werkzeugen wie SVGO um überflüssige Punkte und Attribute erleichtern, was die Rasterung beschleunigt und nebenbei die Datei verkleinert. Endlosschleifen, die außerhalb des sichtbaren Bereichs weiterlaufen, kosten Rechenzeit und Akku, ohne dass jemand etwas davon hat, und gehören pausiert. Ob eine Animation tatsächlich flüssig läuft, zeigt am Ende nur eine Messung im Performance-Panel der Entwicklerwerkzeuge, möglichst mit gedrosselter CPU.
Eine Studie der Johns Hopkins University fand 2009 bei 35,4 Prozent der US-Erwachsenen ab 40 Jahren messbare Störungen der vestibulären Funktion, also des Gleichgewichtssinns (1). Nicht jede dieser Störungen macht Bildschirmbewegung zum Problem. Für viele Betroffene können aber großflächige Zooms, Parallax-Effekte oder rotierende Elemente Schwindel und Übelkeit auslösen. Betriebssysteme bieten deshalb eine Einstellung, Bewegung zu reduzieren, und CSS kann sie über die Media Query prefers-reduced-motion abfragen:
@media (prefers-reduced-motion: reduce) {
.signet path {
animation: none;
stroke-dashoffset: 0;
}
.menu-toggle .bar {
transition: none;
}
}
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
animation.finish();
}
Reduzieren darf dabei behutsam ausfallen. Ein sanftes Einblenden ist meist unproblematisch, wo ein Flug quer über den Bildschirm es nicht ist. Entscheidend ist, dass der Endzustand sichtbar bleibt: Das Signet muss vollständig erscheinen, auch wenn es sich nicht zeichnet. Eine Tücke betrifft SMIL: Die Media Query greift nur auf CSS, SMIL-Animationen laufen unbeeindruckt weiter. Dort hilft ein Skript, das über pauseAnimations() am svg-Element eingreift, oder die Entscheidung, für diesen Fall gleich auf CSS zu setzen.
Hinzu kommt eine formale Vorgabe. Nach WCAG 2.2, Erfolgskriterium 2.2.2, brauchen Inhalte, die sich automatisch bewegen, länger als fünf Sekunden laufen und neben anderen Inhalten stehen, eine Möglichkeit zum Anhalten (2). Das betrifft gerade die dekorativen Endlosschleifen, die in Heroes und Hintergründen gern unauffällig mitlaufen. Für Screenreader gilt ohnedies: Eine rein dekorative Animation bekommt aria-hidden=„true“, und Zustandsänderungen werden über die Semantik des steuernden Elements vermittelt, nicht über die Grafik. Warum dabei weniger ARIA oft die bessere Wahl ist, gilt für animierte Icons genauso wie für statische.
Eine gelungene Animation erklärt, was sich verändert hat: woher ein Menü kommt, dass ein Formular angekommen ist, welcher Wert in einem Diagramm gewachsen ist. Für Microinteractions haben sich Dauern zwischen etwa 150 und 300 Millisekunden bewährt. Alles darüber mag beim ersten Mal elegant wirken und fühlt sich beim zehnten Mal wie Wartezeit an. Das Logo, das sich beim Seitenaufruf selbst zeichnet, ist beim Erstbesuch eine schöne Geste und beim fünften eine Verzögerung, um die niemand gebeten hat.
SVG macht Bewegung technisch so zugänglich wie kaum ein anderes Format im Web, und genau darin liegt die Versuchung. Die meisten Oberflächen gewinnen mehr durch zwei präzise gesetzte Übergänge als durch zwanzig beeindruckende. Bewegung verhält sich in einer Oberfläche wie Interpunktion in einem Text: Man bemerkt sie erst, wenn sie fehlt oder wenn es zu viel davon gibt.