SVG hero animations with pure CSS — zero JavaScript
11 min read

SVG Hero-Animationen ohne JavaScript: Seiten-spezifische visuelle Identitäten

#SVG #CSS Animation #Performance

Die meisten Hero-Sektionen im Web folgen einem vorhersehbaren Muster: ein statisches Hintergrundbild, vielleicht mit einem CSS-Gradient darüber, oder — wenn das Budget groß genug ist — eine JavaScript-Animationsbibliothek wie GSAP, Lottie oder Three.js. Beide Ansätze haben Kompromisse. Statische Bilder sind langweilig und austauschbar. JavaScript-Bibliotheken blähen das Bundle auf, blockieren den Main Thread und erzeugen oft Accessibility-Probleme.

Es gibt einen dritten Weg: reine SVG + CSS @keyframes. Dieses Portfolio verwendet genau diesen Ansatz, um sechs einzigartige, seitenspezifische Hero-Hintergründe zu erzeugen — jeder mit eigenem visuellen Charakter, null JavaScript-Overhead und vollständiger prefers-reduced-motion-Unterstützung.

Was diesen Ansatz besonders macht: Jede Seite hat nicht nur ein anderes Farbschema oder Layout, sondern eine grundlegend andere visuelle Metapher. Die Homepage zeigt einen Code-Editor. Die About-Seite ein Konstellations-Netzwerk. Die Kontakt-Seite pulsierende Signal-Wellen. Die visuelle Identität jeder Seite wird durch ihre Animation definiert — nicht durch austauschbare Stock-Fotos.

SVG-Animationen mit CSS sind die am meisten unterschätzte Technik im modernen Webdesign. Sie kombinieren Dateigröße nahe Null mit unbegrenzter kreativer Flexibilität.

Sarah Drasner VP of Developer Experience, Netlify

Warum SVG + CSS statt JavaScript-Bibliotheken?

6
Hero-Visuals
Dieses Portfolio
0 KB
JavaScript
Null Runtime
< 5 KB
Pro SVG (gzipped)
Netzwerk-Payload

Die Entscheidung für SVG + CSS ist keine Stilfrage — es ist eine technische Entscheidung mit messbaren Vorteilen. Animations-Bibliotheken wie GSAP (43 KB minified), Lottie (250 KB+ mit Player) oder Anime.js (17 KB) fügen Laufzeit-Overhead hinzu, der den Main Thread blockiert. SVG-Animationen mit CSS werden dagegen vom Browser-Compositor auf der GPU ausgeführt — sie berühren den Main Thread nicht einmal.

Dazu kommt ein oft übersehener Aspekt: Dependency-Management. Eine JavaScript-Bibliothek muss aktualisiert, auf Breaking Changes geprüft und gegen Sicherheitslücken gepatcht werden. CSS @keyframes haben keine Versionen, keine Dependencies und keine CVEs. Sie sind ein nativer Bestandteil der Web-Plattform und funktionieren in jedem Browser — heute und in zehn Jahren.

Kriterium SVG + CSS Recommended Lottie GSAP Canvas/WebGL
Bundle-Größe 0 KB JS ~250 KB ~43 KB ~50-200 KB
Rendering GPU Compositing Canvas/SVG DOM/WAAPI GPU (WebGL)
Barrierefreiheit Nativ (aria-hidden) Begrenzt Manuell Keine
prefers-reduced-motion CSS Media Query JS-Check nötig JS-Check nötig JS-Check nötig
Interaktivität Hover/Focus CSS Volle Kontrolle Volle Kontrolle Volle Kontrolle
Browser-Support 98%+ (alle modernen) 95%+ 97%+ 93%+
SEO-Impact Keiner (kein JS) Minimal Minimal Keiner
Lernkurve CSS-Kenntnisse After Effects + JSON JS-API WebGL/Shader
Dependencies Keine 1+ npm-Pakete 1+ npm-Pakete 1-3 npm-Pakete
Wartungsaufwand Null Updates nötig Updates nötig Updates nötig

Der entscheidende Punkt: Für dekorative Hero-Hintergründe, die keine komplexe Interaktivität benötigen, ist SVG + CSS die überlegene Lösung. Du bekommst flüssige 60fps-Animationen, null JavaScript-Payload und native Accessibility-Features — gratis. Wie sich das konkret auf Core Web Vitals auswirkt, zeigt mein Performance-Guide.

Die 6 Hero-Visuals im Überblick

Jede Seite dieses Portfolios hat einen eigenen, thematisch passenden Hero-Hintergrund. Die Visuals nutzen SVG-Elemente, CSS-Animationen und absolute Positionierung, um einen subtilen, lebendigen Hintergrund zu schaffen, der den Inhalt unterstreicht, ohne abzulenken. Keines der Visuals ist rein dekorativ im Sinne von “hübsch” — jedes transportiert eine inhaltliche Botschaft über die jeweilige Seite.

Code-Editor Hero-Visual
HeroVisual — Homepage

Ein animierter Code-Editor mit Syntax-Highlighting, blinkender Schreibkursor und einem überlappenden Terminal-Fenster. Die roten, gelben und grünen Punkte der Title-Bar imitieren ein macOS-Fenster. Darunter werden Astro-Codezeilen mit farbig hervorgehobenen Tags, Attributen und Strings dargestellt. Schwebende geometrische Formen — ein leuchtender Kreis, ein Ring und pulsierende Punkte — umgeben den Editor und erzeugen räumliche Tiefe. Das Terminal zeigt einen erfolgreichen Build-Output mit Häkchen-Symbolen.

Konstellations-Hero-Visual
AboutHeroVisual — Über mich

Ein Konstellations-Netzwerk mit einem zentralen leuchtenden Kern, drei konzentrischen Ringen, die pulsierend expandieren, und acht Knotenpunkten, die über gestrichelte SVG-Linien verbunden sind. Schwebende Tech-Labels wie Astro, React, WordPress, SEO, A11y und TypeScript schweben über der Szene. Zwei Ambient-Gradient-Blobs erzeugen farbige Nebel-Effekte. Die Kernposition wird bei jedem Seitenaufruf über ein JavaScript-Snippet randomisiert, das sechs vordefinierte Zonen verwendet.

Portfolio-Hero-Visual
PortfolioHeroVisual — Portfolio

Ein versetztes Raster aus neun rechteckigen Kacheln, die wie abstrakte Projekt-Thumbnails wirken. Jede Kachel pulsiert mit einem subtilen Fade-In/Out-Effekt und wächst leicht auf 103% ihrer Ursprungsgröße. Fünf diagonale SVG-Gitterlinien durchziehen die Szene mit gestrichelten Strichen. Schwebende Kategorie-Labels — Web, Branding, UI/UX, SEO, E-Commerce — und dekorative Eck-Klammern oben links und unten rechts rahmen die Komposition ein.

Blog-Typewriter-Hero-Visual
BlogHeroVisual — Blog

Abstrakte horizontale Textzeilen in verschiedenen Breiten (45-90%) imitieren geschriebene Absätze. Zwei Gruppen dieser Textlinien schweben an unterschiedlichen Stellen. Ein blinkender Cursor-Balken (2x18px) deutet aktives Schreiben an. Große schwebende Anführungszeichen in 80px Georgia-Serif und Topic-Labels wie Design, Code, A11y, Performance und CSS vollenden die Schreibatmosphäre.

Kontakt-Briefumschlag-Hero-Visual
ContactHeroVisual — Kontakt

Radiating Signal-Bögen breiten sich konzentrisch von einem leuchtenden Fokuspunkt aus — wie ein expandierendes WiFi-Signal. Vier Kreisringe (60px, 120px, 200px, 300px Durchmesser) mit zeitlich versetzten Ripple-Animationen (0s, 0.6s, 1.2s, 1.8s Delay) erzeugen eine kontinuierliche Welle visueller Energie. Zwei SVG-Briefumschlag-Outlines schweben leicht geneigt über die Fläche. Sechs verstreute Verbindungspunkte und vier schwebende Labels unterstreichen den Kommunikations-Charakter.

Rechts-Schild-Hero-Visual
LegalHeroVisual — Rechtliches

Zwei abstrakte Dokument-Outlines mit einem dickeren Header-Balken und je vier bis fünf dünneren Textzeilen imitieren rechtliche Schriftstücke. Zwei SVG-Schild-Symbole — eines mit Häkchen für Compliance, eines ohne für offene Anforderungen — schweben über der Szene. Drei große Paragraphen-Zeichen (§) in 35-60px und fünf schwebende Labels wie DSGVO, WCAG, TMG, BFSG und DDG verankern das Visual thematisch im Rechtsbereich.

Anatomie eines SVG-Hero-Backgrounds

Der Aufbau jedes Hero-Visuals folgt einem konsistenten Muster. Die einzelnen Schritte wiederholen sich in jeder Variante, nur die konkreten SVG-Elemente und Animationen ändern sich. Diese Konsistenz ist kein Zufall — sie ermöglicht es, neue Visuals in unter einer Stunde zu erstellen, weil die Architektur bereits steht.

5 Schritte zum animierten Hero-Hintergrund

  1. Container mit absolutem Positioning

    Der äußere Container wird mit position: absolute und inset: 0 über den gesamten Hero-Bereich gespannt. pointer-events: none stellt sicher, dass der Hintergrund keine Klicks abfängt. aria-hidden="true" markiert ihn als rein dekorativ — Screenreader ignorieren ihn komplett. overflow: hidden verhindert, dass Elemente über den Hero-Bereich hinausragen.

  2. SVG viewBox und preserveAspectRatio

    SVG-Elemente wie Verbindungslinien oder Gitter nutzen ein viewBox="0 0 800 500" mit preserveAspectRatio="xMidYMid slice". Das viewBox definiert ein virtuelles Koordinatensystem, das unabhängig von der tatsächlichen Containergröße funktioniert. slice füllt den Container vollständig aus und schneidet überstehende Teile ab — ähnlich wie object-fit: cover für Bilder.

  3. CSS @keyframes für Animationen

    Jedes Visual definiert eigene @keyframes — float, pulse, orbit, blink, shimmer, ripple. Die Animationen nutzen ausschließlich transform und opacity, da nur diese beiden Properties GPU-beschleunigte Compositing-Animationen erzeugen. Kein width, height, top oder left in den Keyframes — das würde Layout-Recalculations triggern und die Performance zerstören.

  4. animation-delay für organisches Gefühl

    Gleichzeitig pulsierende Elemente wirken mechanisch und künstlich. Durch gestaffelte animation-delay-Werte (0s, 0.3s, 0.6s, 0.9s...) starten die Animationen zeitlich versetzt. Das erzeugt einen organischen, lebendigen Rhythmus, als wären die Elemente voneinander unabhängig. Die Delay-Werte sind bewusst unregelmäßig gewählt, um Muster zu vermeiden.

  5. prefers-reduced-motion Media Query

    Am Ende jedes Style-Blocks steht ein @media (prefers-reduced-motion: reduce) Block, der sämtliche Animationen mit animation: none deaktiviert. Nutzer, die in ihren Betriebssystem-Einstellungen reduzierte Bewegung aktiviert haben, sehen einen statischen Hintergrund — die visuellen Elemente bleiben sichtbar, bewegen sich aber nicht.

Das grundlegende Container-Pattern

Jedes Hero-Visual folgt demselben HTML-Grundgerüst. Hier am Beispiel des einfachsten Visuals — eine vereinfachte Darstellung des Blog-Hero-Hintergrunds:

<!-- Äußerer Container: überdeckt den gesamten Hero-Bereich -->
<div class="blog-bg" aria-hidden="true">
  <!-- Schicht 1: Ambient-Hintergrund (Blobs, Gradients) -->
  <div class="blog-bg__blob blog-bg__blob--1"></div>
  <div class="blog-bg__blob blog-bg__blob--2"></div>

  <!-- Schicht 2: SVG-Elemente (Linien, Formen, Pfade) -->
  <svg class="blog-bg__lines" viewBox="0 0 800 500"
       preserveAspectRatio="xMidYMid slice">
    <!-- SVG-Inhalte hier -->
  </svg>

  <!-- Schicht 3: HTML-Elemente (Punkte, Labels, Cursor) -->
  <div class="blog-bg__cursor"></div>
  <span class="blog-bg__label blog-bg__label--1">Design</span>
</div>
/* Container spannt sich über den gesamten Hero */
.blog-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

Das z-index: 0 stellt sicher, dass der Hero-Inhalt (Überschrift, Buttons) mit einem höheren z-index darüber liegt. pointer-events: none verhindert, dass der dekorative Hintergrund Maus- oder Touch-Events abfängt, die für die darüberliegenden interaktiven Elemente bestimmt sind.

CSS-Animationstechniken

Die sechs Hero-Visuals verwenden vier grundlegende Animationstypen, die sich in verschiedenen Varianten kombinieren lassen. Alle nutzen ausschließlich transform und opacity — die einzigen Properties, die der Browser ohne Layout-Recalculation auf der GPU animieren kann.

/* Float — sanftes Auf- und Abschweben */
/* Erzeugt den Eindruck von Schwerelosigkeit */
@keyframes hero-float {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-12px);
  }
}

/* Anwendung mit verschiedenen Dauern und Richtungen */
.shape--circle {
  animation: hero-float 6s ease-in-out infinite;
}

.shape--ring {
  /* reverse kehrt die Richtung um — Elemente bewegen
     sich gegenläufig für mehr visuelle Spannung */
  animation: hero-float 8s ease-in-out infinite reverse;
}

/* Tipp: Verschiedene Dauern (6s, 7s, 8s, 9s)
   erzeugen ein nie-wiederholendes Muster,
   weil die Phasen nie exakt synchron sind */
/* Pulse — atmendes Skalieren mit Opacity */
/* Simuliert ein sanftes Leuchten/Pulsieren */
@keyframes hero-pulse {
  0%, 100% {
    opacity: 0.3;
    transform: scale(1);
  }
  50% {
    opacity: 0.6;
    transform: scale(1.5);
  }
}

/* Anwendung mit gestaffeltem Delay */
.dot--1 {
  animation: hero-pulse 3s ease-in-out infinite;
  animation-delay: 0s;
}
.dot--2 {
  animation: hero-pulse 3s ease-in-out infinite;
  animation-delay: 1s;
}
.dot--3 {
  animation: hero-pulse 3s ease-in-out infinite;
  animation-delay: 2s;
}

/* Die gestaffelten Delays (0s, 1s, 2s) erzeugen
   eine Wellenbewegung durch die Punkte */
/* Ripple — expandierende Kreisringe (Kontakt-Seite) */
/* Simuliert Wellen, die sich von einem Punkt ausbreiten */
@keyframes contact-ripple {
  0% {
    transform: translate(-50%, -50%) scale(0.8);
    opacity: 0.2;
  }
  100% {
    transform: translate(-50%, -50%) scale(1.15);
    opacity: 0;
  }
}

/* Vier Ringe mit gestaffeltem Delay = Endlos-Welle */
.arc--1 {
  width: 60px; height: 60px;
  animation: contact-ripple 3s ease-out infinite;
}
.arc--2 {
  width: 120px; height: 120px;
  animation: contact-ripple 3s ease-out infinite 0.6s;
}
.arc--3 {
  width: 200px; height: 200px;
  animation: contact-ripple 3s ease-out infinite 1.2s;
}
.arc--4 {
  width: 300px; height: 300px;
  animation: contact-ripple 3s ease-out infinite 1.8s;
}
/* Cursor Blink — steps() für diskretes Blinken */
/* step-end erzeugt abrupte Übergänge statt smooth */
@keyframes hero-blink {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

.cursor {
  display: inline-block;
  width: 7px;
  height: 14px;
  background: var(--color-primary-500);
  /* step-end = sofortiger Wechsel, kein Fading
     Das ist realistischer als ein weiches Überblenden,
     weil echte Cursor auch abrupt blinken */
  animation: hero-blink 1.2s step-end infinite;
  vertical-align: text-bottom;
}

/* Im Terminal: leicht kleinere Variante */
.cursor--term {
  width: 6px;
  height: 12px;
  margin-left: 4px;
}

Warum nur transform und opacity?

Browser rendern Animationen in einer Pipeline: Style > Layout > Paint > Composite. Die meisten CSS-Properties (width, height, top, left, margin, padding, border) triggern die komplette Pipeline ab dem Layout-Schritt. Jeder Frame muss neu berechnet werden, was auf dem Main Thread passiert und JavaScript blockiert.

transform und opacity sind besonders: Sie triggern nur den Composite-Schritt. Der Browser erstellt einen separaten GPU-Layer für das Element und verschiebt, skaliert oder blendet es dort ein — ohne den Main Thread zu berühren. Das ist der Grund, warum CSS-Animationen mit diesen Properties flüssige 60fps erreichen, selbst wenn der Main Thread mit JavaScript beschäftigt ist.

Deep Dive: Das Konstellations-Visual

Das AboutHeroVisual ist das komplexeste der sechs Visuals. Es kombiniert mehrere Techniken zu einem zusammenhängenden Netzwerk-Effekt, der Arnolds vernetzte Fähigkeiten visuell repräsentiert. Schauen wir uns die einzelnen Schichten im Detail an.

Aufbau der fünf Schichten

Das Visual besteht aus fünf Schichten, die übereinander gestapelt werden. Die Reihenfolge im DOM bestimmt die visuelle Tiefe:

  1. Ambient-Blobs (z-index: auto) — Große, unscharfe Farbflächen (filter: blur(80px)) erzeugen einen subtilen Nebel-Effekt im Hintergrund. Zwei Blobs in --color-primary-600 und --color-secondary-600 bei 5-6% Opacity.
  2. SVG-Verbindungslinien (z-index: auto) — Gestrichelte Linien (stroke-dasharray: 4 6) verbinden die Knotenpunkte mit dem Zentrum. Acht Linien zum Kern, plus vier Querverbindungen zwischen äußeren Knoten.
  3. Knotenpunkte (z-index: auto) — Acht 6x6px große Kreise an festen Positionen, die mit about-node-glow zwischen 25% und 50% Opacity pulsieren. Jeder Knoten hat einen individuellen animation-delay.
  4. Zentraler Kern (z-index: 2) — Ein 12px-Punkt mit box-shadow-Glow und drei konzentrischen Ringen (80px, 160px, 280px Durchmesser), die mit about-ring-pulse pulsieren.
  5. Tech-Labels (z-index: auto) — Sechs schwebende Text-Labels (Astro, React, WordPress, SEO, A11y, TypeScript) in Monospace-Schrift bei 18% Opacity.

Die pulsierenden Ringe im Detail

/* Drei konzentrische Ringe um den Kern */
.core-ring--1 {
  width: 80px;
  height: 80px;
  opacity: 0.2;
  animation: about-ring-pulse 4s ease-in-out infinite;
}

.core-ring--2 {
  width: 160px;
  height: 160px;
  opacity: 0.1;
  animation: about-ring-pulse 4s ease-in-out infinite 1s;
}

.core-ring--3 {
  width: 280px;
  height: 280px;
  opacity: 0.06;
  animation: about-ring-pulse 4s ease-in-out infinite 2s;
}

/* Private Custom Property steuert die Basis-Opacity jedes Rings */
.core-ring--1 { --_ring-opacity: 0.2; }
.core-ring--2 { --_ring-opacity: 0.1; }
.core-ring--3 { --_ring-opacity: 0.06; }

@keyframes about-ring-pulse {
  0%, 100% {
    transform: translate(-50%, -50%) scale(1);
    opacity: var(--_ring-opacity, 0.15);
  }
  50% {
    transform: translate(-50%, -50%) scale(1.08);
    opacity: calc(var(--_ring-opacity, 0.15) * 0.6);
  }
}

Beachte den Trick mit --_ring-opacity: Jeder Ring definiert seinen eigenen Opacity-Wert als private Custom Property (--_ring-opacity), den die Animation dann per var() und calc() ausliest. So kann eine einzige @keyframes-Definition verschiedene Basis-Opacities animieren — DRY in CSS-Animationen. Die 0.6-Multiplikation bedeutet: Am Höhepunkt der Pulsation sinkt die Opacity auf 60% ihres Basiswerts, was ein subtiles “Atmen” erzeugt.

Die wandernden SVG-Linien

.about-bg__line {
  stroke: var(--color-primary-500);
  stroke-width: 0.5;
  opacity: 0.08;
  stroke-dasharray: 4 6;
  animation: about-line-dash 20s linear infinite;
}

/* Querverbindungen sind noch subtiler */
.about-bg__line--faint {
  opacity: 0.04;
  stroke-dasharray: 2 8;
}

@keyframes about-line-dash {
  0% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 100; }
}

stroke-dasharray: 4 6 erzeugt ein Muster aus 4px Strich und 6px Lücke. Die Animation verschiebt dann den stroke-dashoffset linear, wodurch die Striche durch die Linie zu wandern scheinen. Bei 20 Sekunden Dauer ist die Bewegung so subtil, dass sie eher gefühlt als bewusst wahrgenommen wird — genau der richtige Level für einen dekorativen Hintergrund.

Die Querverbindungen (--faint) verwenden stroke-dasharray: 2 8 — kürzere Striche mit größeren Lücken — und nur 4% Opacity. Sie sind fast unsichtbar, erzeugen aber unbewusst den Eindruck eines dichteren Netzwerks.

Randomisierung der Kern-Position

Ein subtiles Detail: Die Position des zentralen Kerns wird bei jedem Seitenaufruf randomisiert. Das geschieht über ein kleines JavaScript-Snippet, das CSS Custom Properties setzt:

/* Sechs vordefinierte Zonen — keine Position im Text-Bereich */
const zones = [
  { top: [15, 35], left: [5, 25] },    /* oben links */
  { top: [15, 35], left: [75, 92] },   /* oben rechts */
  { top: [60, 85], left: [5, 25] },    /* unten links */
  { top: [60, 85], left: [75, 92] },   /* unten rechts */
  { top: [15, 35], left: [40, 60] },   /* oben mitte */
  { top: [70, 85], left: [40, 60] },   /* unten mitte */
];

/* Zufällige Zone wählen, Position innerhalb berechnen */
const zone = zones[Math.floor(Math.random() * zones.length)];
bg.style.setProperty('--core-top', `${coreTop}%`);
bg.style.setProperty('--core-left', `${coreLeft}%`);

Die Zonen sind so gewählt, dass der Kern niemals über dem Haupttext des Hero-Bereichs landet (30-70% auf beiden Achsen). So bleibt der Text immer lesbar, während das Visual bei jedem Besuch anders aussieht. Die SVG-Verbindungslinien werden anschließend aktualisiert, damit sie zum neuen Mittelpunkt zeigen.

Performance-Überlegungen

Die Animations-Performance ist kein Zufall — sie ist das Ergebnis bewusster technischer Entscheidungen, die bei jedem Visual konsistent angewendet werden.

Nur Compositing

Alle Animationen nutzen ausschließlich transform und opacity — die einzigen Properties, die der Browser auf der GPU animieren kann, ohne das Layout neu zu berechnen.

Kein Layout Thrash

Kein width, height, top, left oder margin in @keyframes. Diese Properties triggern Layout-Recalculations, die den Main Thread blockieren und Jank verursachen.

GPU-beschleunigt

transform und opacity werden auf einem separaten Compositing-Layer gerendert. Der Main Thread bleibt frei für JavaScript, Event-Handling und andere Aufgaben.

Above-the-fold Only

Hero-Visuals sind nur im sichtbaren Viewport aktiv. Keine versteckten Animationen unterhalb des Folds, die Batterie und CPU verschwenden.

< 5 KB gzipped

Jedes Visual ist unter 5 KB komprimierter HTML+CSS. Zum Vergleich: Ein JPEG-Hintergrundbild in 1920px Breite wäre 50-200 KB. Lottie-JSON typischerweise 30-100 KB.

Keine JS-Runtime

Null JavaScript wird für die Animationen benötigt. Kein requestAnimationFrame-Loop, kein Tween-Engine, kein Event-Listener. Der Browser-Compositor erledigt alles nativ.

will-change: Braucht man es?

Eine häufige Frage: Sollte man will-change: transform auf die animierten Elemente setzen? Die Antwort ist differenziert:

  • Nicht nötig, wenn du bereits animation oder transition mit transform verwendest — der Browser promoted das Element automatisch auf einen GPU-Layer.
  • Potenziell schädlich, wenn du will-change auf zu viele Elemente setzt — jeder GPU-Layer verbraucht Videospeicher. Bei 20+ animierten Elementen kann das auf Mobile-Geräten mit begrenztem VRAM zum Problem werden.
  • Nützlich nur bei Hover-Transitionen, die beim ersten Trigger einen Frame-Drop verursachen, weil der Layer erst erstellt werden muss.

In diesem Portfolio wird will-change nicht verwendet — die animation-Property reicht aus, um die Layer-Promotion zu triggern.

Barrierefreiheit

Dekorative Animationen dürfen niemals die Zugänglichkeit beeinträchtigen. Die Hero-Visuals implementieren drei Schichten der Barrierefreiheit.

1. aria-hidden=“true”

Jedes Hero-Visual hat aria-hidden="true" auf dem äußersten Container. Das bedeutet: Screenreader-Nutzer erfahren nichts von diesen Elementen. Da die Visuals rein dekorativ sind und keinen inhaltlichen Mehrwert bieten, ist das korrekt — ein Screenreader, der „div, div, div, svg, line, line, span, Astro, span, React” vorliest, hilft niemandem.

Wichtig: aria-hidden="true" auf dem Container vererbt sich automatisch auf alle Kinder. Du musst es nicht auf jedes einzelne Element setzen. Ein einziges Attribut auf dem Wrapper reicht aus.

2. prefers-reduced-motion

@media (prefers-reduced-motion: reduce) {
  .about-bg__core-ring,
  .about-bg__node,
  .about-bg__line,
  .about-bg__label,
  .about-bg__blob {
    animation: none;
  }
}

Dieser CSS-Media-Query reagiert auf die Betriebssystem-Einstellung des Nutzers. Unter macOS: Systemeinstellungen > Bedienungshilfen > Anzeige > „Bewegung reduzieren”. Unter Windows: Einstellungen > Erleichterte Bedienung > Anzeige > „Animationen in Windows anzeigen”. Unter iOS: Einstellungen > Bedienungshilfen > Bewegung > „Bewegung reduzieren”. Die SVG-Elemente bleiben sichtbar, aber statisch.

3. Inhalte bleiben zugänglich

Alle Textinhalte im Hero (Überschrift, Untertitel, CTA-Buttons) liegen über dem dekorativen Hintergrund im DOM. Sie sind vollständig mit Tastatur erreichbar, haben korrekte Heading-Hierarchie und funktionieren identisch mit und ohne die Visuals. Der pointer-events: none auf dem Hintergrund-Container stellt sicher, dass kein dekoratives Element versehentlich den Fokus erhält oder Touch-Events abfängt.

Dark Mode Kompatibilität

Die Hero-Visuals nutzen CSS Custom Properties (Design Tokens) für alle Farbwerte. Das bedeutet: Sie passen sich automatisch an den aktiven Theme-Modus an, ohne zusätzlichen Code.

/* Basis-Styles nutzen Token — passt sich automatisch an */
.about-bg__node {
  background: var(--color-primary-400);
}

.about-bg__line {
  stroke: var(--color-primary-500);
  opacity: 0.08;
}

/* Kern-Glow im Dark Mode */
.about-bg__core-dot {
  box-shadow:
    0 0 20px var(--color-primary-500),
    0 0 60px rgba(1, 95, 252, 0.3);
}

/* Light-Mode-Overrides für feinere Kontrolle */
[data-theme="light"] .about-bg__node {
  background: var(--color-primary-500);
}

[data-theme="light"] .about-bg__line {
  stroke: var(--color-primary-600);
  opacity: 0.06;
}

/* Reduzierter Glow im Light Mode */
[data-theme="light"] .about-bg__core-dot {
  box-shadow:
    0 0 20px var(--color-primary-500),
    0 0 40px rgba(1, 95, 252, 0.15);
}

Das Prinzip ist einfach: Die Basis-Styles nutzen Token-Werte, die bereits für den Dark Mode definiert sind (--color-primary-400, --color-primary-500). Für den Light Mode werden [data-theme="light"]-Selektoren mit leicht angepassten Werten verwendet — typischerweise dunklere Farbtöne und reduzierte Opacity, da helle Hintergründe weniger Kontrast vertragen.

Responsive Anpassungen

Die Hero-Visuals skalieren nicht einfach herunter — sie werden auf kleinen Bildschirmen bewusst vereinfacht, um visuelles Rauschen zu reduzieren und die Performance auf mobilen Geräten zu schonen.

Mobile Breakpoints

Alle Visuals haben einen @media (max-width: 639px) Block, der bestimmte Elemente verkleinert oder vereinfacht:

  • Fonts werden von 10px auf 8px reduziert (schwebende Labels)
  • Blobs werden von 250-300px auf 130-180px geschrumpft
  • Konzentrische Ringe reduzieren ihren Radius (z.B. 280px auf 180px)
  • Decorative Brackets werden von 40px auf 24px verkleinert
  • Quotation Marks werden von 80px auf 50px verkleinert
  • Text-Linien-Gruppen werden von 140px auf 100px Breite reduziert

Das Ziel: Auf Mobilgeräten soll der Hintergrund spürbar, aber nicht aufdringlich sein. Kein Element wird komplett ausgeblendet — das würde die visuelle Identität der Seite zerstören.

Warum viewBox funktioniert

SVG-Elemente mit viewBox="0 0 800 500" und preserveAspectRatio="xMidYMid slice" skalieren automatisch mit ihrem Container. Die Koordinaten x1="640" y1="200" bleiben relativ zum 800x500-Koordinatensystem — egal, ob der Container 1920px oder 320px breit ist.

Das bedeutet: Keine Media Queries für SVG-Positionierung nötig. Die Linien, Gitter und Formen passen sich proportional an. Der slice-Wert ist entscheidend: Er füllt den Container vollständig aus (wie object-fit: cover), anstatt Letterboxing zu erzeugen (meet wäre das Äquivalent zu contain).

Auf einem schmalen Mobilbildschirm werden die SVG-Inhalte an den Seiten beschnitten — genau wie ein Hintergrundbild mit background-size: cover.

Warum CSS-Animationen mobilfreundlich sind

CSS-Animationen von transform und opacity werden auf Mobile-GPUs genauso effizient gerendert wie auf Desktop-GPUs. Der Schlüssel ist der Compositor: Mobile Browser haben dedizierte Compositing-Layer für transform-Animationen.

Im Gegensatz dazu müsste eine JavaScript-basierte Animation den Main Thread wecken, Berechnungen durchführen und das DOM manipulieren — auf einem 2-3 Jahre alten Smartphone ein spürbarer Performance-Unterschied.

Ein zusätzlicher Vorteil: CSS-Animationen werden automatisch pausiert, wenn der Browser-Tab nicht sichtbar ist (Page Visibility API). Das spart Batterie auf Mobilgeräten — ein Bonus, den viele JavaScript-Animationen nicht bieten, weil sie den requestAnimationFrame-Loop manuell pausieren müssen.

Entwicklungs-Workflow in Astro

Die Hero-Visuals sind als Astro-Komponenten in der Molecules-Schicht der Atomic Design Hierarchie implementiert. Jede Komponente ist eine eigenständige .astro-Datei mit eingebetteten Scoped Styles. Die Einordnung als Molecules (und nicht als Atoms oder Organisms) folgt einer klaren Logik: Sie kombinieren mehrere primitive Elemente (SVG-Shapes, Divs, Spans) zu einer funktionalen Einheit, sind aber nicht komplex genug für einen Organismus.

Komponente erstellen

Neue .astro-Datei unter src/components/molecules/ anlegen. Interface Props definieren (falls konfigurierbar). SVG-Markup und HTML-Struktur mit aria-hidden="true" aufbauen. BEM-Klassen für alle Elemente definieren.

Scoped Styles schreiben

Alle CSS-Regeln im <style>-Block der Komponente. BEM-Benennung (hero-visual__element--modifier). Design Tokens für alle Farbwerte. @keyframes-Definitionen innerhalb des Scoped-Blocks. Keine !important-Regeln.

@keyframes definieren

Animationen mit transform und opacity. Verschiedene Dauern (3-20s) und Delays (0-2.5s) für organisches Gefühl. ease-in-out für schwebende Bewegungen, ease-out für expandierende Ripples, step-end für Cursor-Blinken, linear für endlose Laufbänder.

prefers-reduced-motion hinzufügen

@media (prefers-reduced-motion: reduce) Block am Ende des Styles. Alle animierten Selektoren auflisten. animation: none setzen. Elemente bleiben sichtbar, nur die Bewegung stoppt. Testen mit den Betriebssystem-Einstellungen.

Dark Mode Overrides

[data-theme="light"] Selektoren für angepasste Opacity und Farbtöne. Typisch: dunklere Token-Stufen (primary-600 statt primary-400) und niedrigere Opacity auf hellem Hintergrund. box-shadow-Glow reduzieren.

Responsive Breakpoints

@media (max-width: 639px) für Mobile-Vereinfachungen. Elementgrößen reduzieren, Schriftgrößen anpassen. Kein Element vollständig ausblenden — nur verkleinern. viewBox-basierte SVGs skalieren automatisch.

Häufig gestellte Fragen

FAQ: SVG Hero-Animationen

Fazit

SVG-Hero-Animationen mit CSS sind keine Kompromisslösung — sie sind die technisch überlegene Wahl für dekorative Hintergründe. Null JavaScript-Payload, GPU-beschleunigte 60fps-Animationen, native prefers-reduced-motion-Unterstützung und unter 5 KB pro Visual. Die sechs seitenspezifischen Visuals in diesem Portfolio beweisen, dass man mit reinem CSS eine starke visuelle Identität schaffen kann, die gleichzeitig performant und barrierefrei ist.

Der Schlüssel liegt in der Disziplin: nur transform und opacity in @keyframes, gestaffelte animation-delay-Werte für organisches Timing und ein konsistenter prefers-reduced-motion-Block in jeder Komponente. Dazu kommen die architektonischen Entscheidungen — aria-hidden="true" auf dem Container, pointer-events: none für Klick-Durchlässigkeit, und viewBox-basierte SVGs für automatische Responsivität.

Das Ergebnis sind lebendige Seiten, die sich anfühlen, als würden sie atmen — ohne dass ein einziges Byte JavaScript dafür nötig ist. Und das Beste: Wenn ein Nutzer reduzierte Bewegung bevorzugt, sieht er einen schönen, statischen Hintergrund statt einer leeren Fläche. Die Visuals funktionieren mit und ohne Animation — das ist inklusives Design.