CSS Animation 101
Alles bewegt sich, du entscheidest wie. Pure CSS, kein JavaScript, echter Wow-Effekt.
Empfohlen nach CSS 101.
Kapitel 01
Transitions — sanfte Übergänge
transition macht den Wechsel zwischen zwei Zuständen flüssig.
.btn, normal.btn:hoverDie Reihenfolge im Befehl: Eigenschaft, Dauer, Kurve, Verzögerung.
transition: background 0.3s ease:hover
Der einfachste Einstieg in CSS-Motion: transition macht den Wechsel zwischen zwei Zuständen flüssig — statt abruptem Schnitt ein weiches Gleiten.
/* Ohne transition: abrupter Sprung */
.btn {
background: #333;
}
.btn:hover {
background: #fa5c7b;
}
/* Mit transition: sanfter Übergang */
.btn {
background: #333;
transition: background 0.3s ease;
/* ^Eigenschaft ^Dauer ^Kurve */
}
.btn:hover {
background: #fa5c7b;
}// Syntax
transition: [property] [duration] [timing-function] [delay]
transition: all 0.3s ease; — animiert ALLE änderbaren Eigenschaften
transition: color 0.2s, transform 0.4s ease-out; — mehrere, kommagetrennt
Was lässt sich per Transition animieren?
Fast alles Numerische: color, background, opacity, transform, width, height, padding, border-radius, box-shadow…
⚠ Performance
Animiere wenn möglich nur transform und opacity — diese laufen auf der GPU und sind butterweich. width, height, top, left triggern Layout-Neuberechnung = Ruckeln.
Kapitel 02
@keyframes — Animationen definieren
Zuerst mit @keyframes festlegen, was passiert. Dann mit animation einem Element zuweisen.
@keyframes meineFadewas bei 0 %, 50 %, 100 % passiert.elementanimation: meineFade 0.6s ease forwards@keyframes0% 50% 100%animation
Mit @keyframes definierst du eine Animations-Choreographie — du bestimmst was bei 0%, 50%, 100% passiert. CSS interpoliert den Rest automatisch.
/* 1. Animation definieren */
@keyframes meineFade {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
/* 2. Animation anwenden */
.element {
animation: meineFade 0.6s ease forwards;
/* ^Name ^Dauer ^Kurve ^Endposition behalten */
}Live-Demos: Die Grundbewegungen
/* Fade */
@keyframes fade { 0%,100% { opacity:1; } 50% { opacity:0.1; } }
/* Slide */
@keyframes slide { 0%,100% { transform: translateX(-30px); } 50% { transform: translateX(30px); } }
/* Spin */
@keyframes spin { to { transform: rotate(360deg); } }
/* Bounce */
@keyframes bounce {
0%,100% { transform: translateY(0); }
40% { transform: translateY(-40px); }
60% { transform: translateY(-20px); }
}
/* Scale + Rotate */
@keyframes scaleRotate {
0%,100% { transform: scale(1); }
50% { transform: scale(1.6) rotate(45deg); }
}Kapitel 03
Animation Properties im Überblick
Jede animation-…-Eigenschaft steuert einen Teil. Die Kurzform fasst sie zusammen.
namewelche Keyframesdurationein Durchlauftiming-functionKurvedelayVerzögerungiteration-countinfinitedirectionalternatefill-modeforwardsplay-statepausedanimation: name duration timing delay iteration direction fill-mode
| Property | Was sie macht | Beispielwert |
|---|---|---|
| animation-name | Welche @keyframes verwenden | fadeIn |
| animation-duration | Wie lange dauert ein Durchlauf | 0.6s / 400ms |
| animation-timing-function | Geschwindigkeitskurve | ease / linear |
| animation-delay | Verzögerung vor Start | 0.2s |
| animation-iteration-count | Wie oft wiederholen | infinite / 3 |
| animation-direction | Richtung der Wiederholung | normal / alternate |
| animation-fill-mode | Zustand vor/nach Animation | forwards / both |
| animation-play-state | Pause/Play per CSS | paused / running |
// Shorthand
animation: name duration timing delay iteration direction fill-mode;
Beispiel: animation: fadeIn 0.5s ease 0.2s 1 normal forwards;
fill-mode — oft vergessen, immer wichtig
/* forwards = Element bleibt im Endzustand der Animation */
.card-einblenden {
opacity: 0;
animation: fadeInUp 0.6s ease forwards;
}
/* Ohne forwards: Element springt nach Ende wieder auf opacity:0 zurück! */Kapitel 04
Timing Functions — die Seele der Animation
Die Timing Function bestimmt, wie sich eine Bewegung anfühlt.
linearmechanisch: Ladebalken, Spinnerease-outkommt an: bremst sanftease-ingeht weg: wird schnellersteps(n)Sprünge: Pixel-Art, Typewriterease ease-in ease-out ease-in-outcubic-bezier()steps()
Die Timing Function entscheidet wie sich ein Objekt anfühlt. Gleiche Strecke, gleiche Zeit — aber komplett andere Wirkung:
| Wert | Charakter | Ideal für |
|---|---|---|
| linear | Konstante Geschwindigkeit, mechanisch | Ladebalken, Spinner |
| ease | Startet langsam, beschleunigt, bremst ab | Allgemein, Default |
| ease-in | Startet langsam, endet schnell | Dinge die "weggehen" |
| ease-out | Startet schnell, bremst sanft ab | Dinge die "ankommen" |
| ease-in-out | Wie ease, aber symmetrischer | Loops, Hover-Effekte |
| cubic-bezier(x,y,x,y) | Vollständige Kontrolle | Bounce, Overshoot, Custom |
| steps(n) | Sprünge statt Übergänge | Pixel-Art, Typewriter |
/* Bounce-Effekt via cubic-bezier */
animation: slideIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
/* ↑ Wert > 1 = Overshoot = Federgefühl */
/* Typewriter via steps */
animation: typing 3s steps(30) infinite;✅ Tipp
cubic-bezier.com — visueller Editor für eigene Kurven. Einfach reinspielen und den generierten Code kopieren!
Kapitel 05
Transform — bewegen, drehen, skalieren
transform ändert, wie ein Element aussieht, ohne das Layout zu verschieben.
translateverschiebenrotatedrehenscalevergrössern, verkleinernDie Reihenfolge zählt: translate rotate scale ergibt etwas anderes als scale rotate translate.
translateX translateYrotate scale skewX
transform ist der beste Freund von CSS-Animationen — GPU-beschleunigt, kein Layout-Reflow, butterweich.
/* Verschieben */
transform: translateX(50px);
transform: translateY(-20px);
transform: translate(10px, -30px);
/* Skalieren */
transform: scale(1.5); /* 150% Grösse */
transform: scaleX(2); /* nur horizontal */
/* Drehen */
transform: rotate(45deg);
transform: rotate(-90deg);
/* Schräg stellen */
transform: skewX(15deg);
/* Kombinieren — Reihenfolge beachten! */
transform: translateY(-10px) rotate(5deg) scale(1.05);⚠ Reihenfolge bei Transform!
translate rotate scale ≠ scale rotate translate — die Operationen beeinflussen sich gegenseitig. Als Faustregel: erst translate, dann rotate, dann scale.
transform-origin — Drehpunkt ändern
/* Standard: Mittelpunkt */
transform-origin: center;
/* Ecke als Drehpunkt (wie Kalender-Seite) */
transform-origin: top left;
/* Exakte Position */
transform-origin: 20px 80%;Kapitel 06
Nützliche Animations-Patterns
Bewährte Muster: kopieren, anpassen, kombinieren.
@keyframes pulse-ringsteps()animation-delay
Pulse — aufmerksamkeitsstarkes Pulsieren
/* PULSE RING */
@keyframes pulse-ring {
0% { box-shadow: 0 0 0 0 rgba(250,92,123,0.5); }
70% { box-shadow: 0 0 0 20px rgba(250,92,123,0); }
100% { box-shadow: 0 0 0 0 rgba(250,92,123,0); }
}
.dot { animation: pulse-ring 1.5s ease-out infinite; }
/* TYPEWRITER */
@keyframes typing { 0%,5% { width:0 } 50%,95% { width: 200px } }
@keyframes blink { 50% { border-color: transparent; } }
.text {
overflow: hidden; white-space: nowrap;
width: 0; border-right: 2px solid currentColor;
animation: typing 3s steps(20) infinite, blink .7s step-end infinite;
}
/* STAGGER — Kinder verzögert einblenden */
.list-item { opacity: 0; animation: fadeIn 0.4s ease forwards; }
.list-item:nth-child(1) { animation-delay: 0.1s; }
.list-item:nth-child(2) { animation-delay: 0.2s; }
.list-item:nth-child(3) { animation-delay: 0.3s; }
/* ... oder mit CSS Custom Properties für n Elemente */Hover-Lift — Card hebt sich beim Hover
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-6px);
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
}Shimmer / Skeleton Loading
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.skeleton {
background: linear-gradient(90deg,
#1f1f23 25%, #2e2e35 50%, #1f1f23 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 6px;
}Kapitel 07
PROJEKT: Deine animierte Profil-Card
Fünf Effekte in einer Datei, nur CSS, ohne JavaScript.
animated-card.htmleine Dateianimated-card.html- Browser
Du baust eine vollständig animierte Profil-Card — nur mit CSS, kein JavaScript. Page-Load Animation, Hover-Effekte, Pulse-Badge, alles.
- Card blendet beim Laden ein (stagger)
- Avatar mit Pulse-Ring-Animation
- Hover hebt die Card an (lift)
- Button mit Shine-Effekt beim Hover
- Badge pulsiert dauerhaft
Erstelle eine Datei animated-card.html und füge den kompletten Code ein:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Meine Animated Card</title>
<style>
/* ── RESET & BASE ── */
* { margin:0; padding:0; box-sizing:border-box; }
body {
min-height: 100vh;
background: #0a0a0f;
display: flex;
align-items: center;
justify-content: center;
font-family: system-ui, sans-serif;
}
/* ── EINBLEND-ANIMATION ── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── CARD ── */
.card {
background: #18181b;
border: 1px solid #2e2e35;
border-radius: 20px;
padding: 36px 32px;
width: 300px;
text-align: center;
transition: transform 0.35s cubic-bezier(0.34,1.56,0.64,1),
box-shadow 0.35s ease;
/* Stagger: Card selbst einblenden */
opacity: 0;
animation: fadeUp 0.6s ease 0.1s forwards;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 30px 60px rgba(0,0,0,0.5);
}
/* ── AVATAR mit PULSE ── */
@keyframes pulse-ring {
0% { box-shadow: 0 0 0 0 rgba(250,92,123,0.6); }
70% { box-shadow: 0 0 0 14px rgba(250,92,123,0); }
100% { box-shadow: 0 0 0 0 rgba(250,92,123,0); }
}
.avatar-wrap {
display: inline-block;
margin-bottom: 20px;
opacity: 0;
animation: fadeUp 0.6s ease 0.25s forwards;
}
.avatar {
width: 80px; height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, #fa5c7b, #a78bfa);
display: flex; align-items: center; justify-content: center;
font-size: 2rem;
animation: pulse-ring 2s ease-out infinite;
}
/* ── NAME & BIO ── */
.name {
font-size: 1.3rem;
font-weight: 700;
color: #f4f4f5;
margin-bottom: 6px;
opacity: 0;
animation: fadeUp 0.6s ease 0.35s forwards;
}
.bio {
font-size: 0.88rem;
color: #71717a;
margin-bottom: 20px;
opacity: 0;
animation: fadeUp 0.6s ease 0.45s forwards;
}
/* ── BADGE ── */
@keyframes badge-pulse {
0%,100% { opacity: 1; }
50% { opacity: 0.5; }
}
.badge {
display: inline-flex; align-items: center; gap: 6px;
background: rgba(250,92,123,0.15);
border: 1px solid rgba(250,92,123,0.4);
color: #fa5c7b;
padding: 4px 12px;
border-radius: 50px;
font-size: 0.78rem;
margin-bottom: 24px;
opacity: 0;
animation: fadeUp 0.6s ease 0.5s forwards;
}
.badge-dot {
width: 6px; height: 6px;
background: #fa5c7b;
border-radius: 50%;
animation: badge-pulse 1.2s ease infinite;
}
/* ── BUTTON mit SHINE ── */
@keyframes shine {
from { left: -100%; }
to { left: 150%; }
}
.btn {
display: block;
background: #fa5c7b;
color: #fff;
border: none;
padding: 12px 28px;
border-radius: 10px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
position: relative;
overflow: hidden;
transition: transform 0.2s ease, background 0.2s;
opacity: 0;
animation: fadeUp 0.6s ease 0.6s forwards;
}
.btn::after {
content: '';
position: absolute;
top: -50%; left: -100%;
width: 60%; height: 200%;
background: rgba(255,255,255,0.25);
transform: skewX(-20deg);
transition: none;
}
.btn:hover::after {
animation: shine 0.5s ease;
}
.btn:hover {
background: #e04460;
transform: scale(1.03);
}
/* ── STATS ── */
.stats {
display: flex;
justify-content: space-around;
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid #2e2e35;
opacity: 0;
animation: fadeUp 0.6s ease 0.7s forwards;
}
.stat-value { font-size: 1.2rem; font-weight: 700; color: #f4f4f5; }
.stat-label { font-size: 0.72rem; color: #71717a; margin-top: 2px; }
</style>
</head>
<body>
<div class="card">
<div class="avatar-wrap">
<div class="avatar">🚀</div>
</div>
<div class="name">Dein Name</div>
<div class="bio">CSS Animator · Creative Coder</div>
<div class="badge">
<span class="badge-dot"></span>
Online
</div>
<button class="btn">Profil ansehen →</button>
<div class="stats">
<div>
<div class="stat-value">42</div>
<div class="stat-label">Projekte</div>
</div>
<div>
<div class="stat-value">128</div>
<div class="stat-label">Followers</div>
</div>
<div>
<div class="stat-value">7</div>
<div class="stat-label">Awards</div>
</div>
</div>
</div>
</body>
</html>Das Aha-Moment
Öffne die Datei im Browser — jedes Element blendet mit Verzögerung ein, der Avatar pulsiert, die Card hebt sich beim Hover, der Button leuchtet auf. Alles pure CSS, zero JavaScript. Das ist die Kraft von @keyframes + transitions kombiniert!
Bonus-Challenges
Wenn du Lust hast, probiere diese Erweiterungen:
- → Tausch das Emoji gegen ein echtes Foto aus (
background-image) - → Füge einen Shimmer-Skeleton hinzu, der 1 Sekunde vor der Card erscheint
- → Animiere die Stat-Zahlen beim Hover der Card (CSS Counter + animation)
- → Baue eine Dark/Light Toggle per
:checked+ CSS (kein JS!)
Kapitel 08
Cheatsheet
Der Spickzettel unten, als Wegweiser.
transition@keyframes + animationtransform