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.
Warum SVG + CSS statt JavaScript-Bibliotheken?
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.
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.
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.
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.
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.
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.
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
- 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.
- 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.
- 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.
- 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.
- 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:
- 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-600und--color-secondary-600bei 5-6% Opacity. - 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. - Knotenpunkte (z-index: auto) — Acht 6x6px große Kreise an festen Positionen, die mit
about-node-glowzwischen 25% und 50% Opacity pulsieren. Jeder Knoten hat einen individuellenanimation-delay. - Zentraler Kern (z-index: 2) — Ein 12px-Punkt mit
box-shadow-Glow und drei konzentrischen Ringen (80px, 160px, 280px Durchmesser), die mitabout-ring-pulsepulsieren. - 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.
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 width, height, top, left oder margin in @keyframes. Diese Properties triggern Layout-Recalculations, die den Main Thread blockieren und Jank verursachen.
transform und opacity werden auf einem separaten Compositing-Layer gerendert. Der Main Thread bleibt frei für JavaScript, Event-Handling und andere Aufgaben.
Hero-Visuals sind nur im sichtbaren Viewport aktiv. Keine versteckten Animationen unterhalb des Folds, die Batterie und CPU verschwenden.
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.
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
animationodertransitionmittransformverwendest — der Browser promoted das Element automatisch auf einen GPU-Layer. - Potenziell schädlich, wenn du
will-changeauf 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.
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.
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.
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.
@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.
[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.
@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
Chrome DevTools: Performance Tab > Aufnahme starten > Seite scrollen > Aufnahme stoppen. Prüfe die Frames-Zeile: Grüne Balken bei 60fps = gut. Rote Balken = Jank. Zusätzlich: Rendering Tab > Paint flashing aktivieren — grünes Flackern über animierten Elementen zeigt Main-Thread-Paints an, die du vermeiden solltest. Für einen schnellen Check: Öffne den FPS-Meter unter Rendering > Frame rendering stats.
Ja, absolut. SVG + CSS funktioniert in jedem Framework. In React erstellst du eine funktionale Komponente, die das SVG-Markup zurückgibt, und schreibst die Styles in einer CSS-Datei oder einem CSS-in-JS-Tool. In Vue nutzt du eine Single File Component mit <template> für das SVG und <style scoped> für die Animationen. Der einzige Unterschied zu Astro: Astros Scoped Styles sind build-time (kein Runtime-Overhead), React/Vue sind runtime.
In diesem Portfolio wird kein Visual komplett ausgeblendet. Stattdessen werden Elementgrößen mit einem @media (max-width: 639px) Breakpoint reduziert: kleinere Blobs, schmalere Fonts, kompaktere Ringe. Das spart GPU-Ressourcen, ohne das visuelle Konzept zu zerstören. Für extrem alte Geräte greift zusätzlich prefers-reduced-motion, das alle Animationen abschaltet.
Safari hat historisch Probleme mit SVG-SMIL-Animationen, aber CSS-Animationen auf SVG-Elementen funktionieren zuverlässig seit Safari 12+. Ein bekannter Quirk: Safari berechnet transform-origin auf SVG-Elementen anders als Chrome/Firefox. Lösung: Verwende translate(-50%, -50%) statt transform-origin: center center auf SVG-Elementen. In diesem Portfolio wird genau dieses Pattern für alle zentrierten Elemente (Ringe, Arcs) verwendet.
Ein typisches Hero-Hintergrundbild in 1920x1080px liegt bei 80-200 KB (JPEG/WebP). Die SVG+CSS-Visuals in diesem Portfolio liegen bei 2-5 KB gzipped pro Seite — das ist eine Ersparnis von 95-98%. Für sechs Seiten spart das insgesamt 400-1100 KB an Netzwerk-Payload. Plus: Keine zusätzlichen HTTP-Requests für Bilddateien, kein Preloading nötig.
Ja, über die CSS-Property animation-play-state. Setze animation-play-state: paused auf den Container oder einzelne Elemente, um die Animation einzufrieren. Das kann über eine CSS-Klasse oder ein data-Attribut gesteuert werden. Beispiel: [data-animations="paused"] .hero-visual * { animation-play-state: paused; }. Die Animationen stoppen sofort an ihrer aktuellen Position.
In Print-Stylesheets werden Animationen vom Browser automatisch ignoriert. Da die Visuals aria-hidden="true" haben, werden sie in den meisten Print-Stylesheets ohnehin mit display: none ausgeblendet. Falls du einen expliziten Print-Block brauchst: @media print { .hero-visual { display: none; } }.
Kopiere eine bestehende Visual-Komponente als Ausgangspunkt. Ändere den BEM-Präfix (z.B. pricing-bg statt about-bg). Ersetze die SVG-Elemente und HTML-Struktur durch dein neues Konzept. Passe die @keyframes-Animationen an. Stelle sicher, dass der prefers-reduced-motion-Block alle neuen animierten Selektoren enthält. Teste in Dark Mode und auf Mobile. Das Grundgerüst (Container, Positioning, Accessibility) bleibt identisch.
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.