Chapter 35: Animations
Animations
Animations are what make websites feel alive, premium, engaging, and memorable.
A transition (what we learned last time) is a very simple, automatic animation between two states (usually hover/focus/click).
A CSS animation (what we are learning today) gives you full control — you can:
- animate over many steps (keyframes)
- repeat forever or a specific number of times
- control timing, delay, direction, fill mode
- animate almost any property (not just hover)
- run automatically when the page loads, when scrolled into view, or when a class is added
In 2026, good animations are subtle, purposeful, and performant — not the flashy 2010s bouncing everything.
Let’s learn it step by step like I’m sitting next to you with VS Code open.
1. Two Main Ways to Create Animations in CSS
| Method | When to use it | Control level | Complexity | Performance |
|---|---|---|---|---|
| transition | Simple state changes (hover, focus, class toggle) | Low | Very easy | Excellent |
| @keyframes + animation | Complex, multi-step, auto-running, looped animations | High | Medium | Excellent (when using transform/opacity) |
Today we focus on @keyframes + animation — the real animation system.
2. Basic Syntax – The Two Parts
Part 1: Define the animation with @keyframes
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@keyframes slideIn { from { transform: translateX(-100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } |
or more steps:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
@keyframes bounce { 0% { transform: translateY(0); } 40% { transform: translateY(-30px); } 60% { transform: translateY(0); } 80% { transform: translateY(-15px); } 100% { transform: translateY(0); } } |
Part 2: Apply the animation to an element
|
0 1 2 3 4 5 6 7 8 9 10 |
.slide-element { animation: slideIn 0.8s ease-out forwards; /* or */ animation: bounce 1.2s ease-in-out infinite; } |
Shorthand:
|
0 1 2 3 4 5 6 |
animation: name duration timing-function delay iteration-count direction fill-mode play-state; |
Most common values:
| Property | Common values | Meaning |
|---|---|---|
| animation-name | slideIn, bounce, fadeIn, etc. | Which @keyframes to use |
| animation-duration | 0.6s, 800ms, 1.2s | How long one cycle takes |
| animation-timing-function | ease, ease-in-out, linear, cubic-bezier(0.68, -0.55, 0.265, 1.55) | Speed curve |
| animation-delay | 0s, 0.3s, 500ms | Wait before starting |
| animation-iteration-count | 1, infinite, 3, 2.5 | How many times to repeat |
| animation-direction | normal, reverse, alternate, alternate-reverse | Play forward/backward |
| animation-fill-mode | none, forwards, backwards, both | What styles to keep before/after animation |
| animation-play-state | running, paused | Pause on hover, etc. |
3. Real, Playable Example – Multiple Animation Styles
index.html
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS Animations – Webliance</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1>CSS @keyframes Animations</h1> <p>Scroll down or wait — see different animations in action</p> <!-- Fade in on load --> <div class="box fade-in"> <h2>Fade In (on page load)</h2> <p>Appears smoothly when page loads</p> </div> <!-- Bounce infinite --> <div class="box bounce"> <h2>Bounce Forever</h2> <p>Playful infinite loop</p> </div> <!-- Slide in from left on hover --> <div class="box slide-on-hover"> <h2>Slide In on Hover</h2> <p>Hover me → slides from left</p> </div> <!-- 3D card flip on hover --> <div class="flip-container"> <div class="flip-card"> <div class="front"> <h2>Hover to Flip</h2> <p>3D card flip animation</p> </div> <div class="back"> <h2>Back Side</h2> <p>You found me! 😄</p> </div> </div> </div> <!-- Pulse button --> <button class="pulse-btn">Pulse Button</button> </div> </body> </html> |
style.css (only animation-focused)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
/* Reset + base */ * { margin:0; padding:0; box-sizing:border-box; } body { font-family: system-ui, sans-serif; background: #f8fafc; color: #1e293b; padding: 60px 20px; min-height: 200vh; /* so we can scroll */ } .container { max-width: 1000px; margin: 0 auto; text-align: center; } h1 { margin-bottom: 3rem; color: #1d4ed8; } /* Base box style */ .box { background: white; border-radius: 16px; padding: 2.5rem; margin: 4rem auto; max-width: 600px; box-shadow: 0 6px 20px rgba(0,0,0,0.08); text-align: center; } /* ── Animation 1: Fade In on load ── */ @keyframes fadeIn { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } .fade-in { animation: fadeIn 1.2s ease-out forwards; } /* ── Animation 2: Infinite Bounce ── */ @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } } .bounce { animation: bounce 1.8s ease-in-out infinite; } /* ── Animation 3: Slide in from left on hover ── */ @keyframes slideFromLeft { from { transform: translateX(-100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } .slide-on-hover { transition: all 0.4s ease; } .slide-on-hover:hover { animation: slideFromLeft 0.6s ease-out forwards; transform-origin: left center; } /* ── Animation 4: 3D Flip on hover ── */ .flip-container { perspective: 1000px; width: 100%; max-width: 400px; margin: 4rem auto; } .flip-card { position: relative; width: 100%; height: 240px; transition: transform 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55); transform-style: preserve-3d; } .flip-container:hover .flip-card { transform: rotateY(180deg); } .front, .back { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; border-radius: 16px; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 2rem; box-shadow: 0 6px 20px rgba(0,0,0,0.08); } .front { background: #3b82f6; color: white; } .back { background: #10b981; color: white; transform: rotateY(180deg); } /* ── Animation 5: Pulsing button ── */ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.08); } 100% { transform: scale(1); } } .pulse-btn { padding: 1.2rem 3rem; background: #ef4444; color: white; border: none; border-radius: 50px; font-size: 1.3rem; font-weight: bold; cursor: pointer; animation: pulse 2s infinite ease-in-out; } |
What You Should Do Right Now
- Open with Live Server
- Scroll slowly → see fade-in on load
- Hover the slide card → watch it come from left
- Hover flip card → see 3D rotation
- Watch the red button pulse forever
- Try changing:
- 1.2s to 2s in fadeIn → slower appearance
- cubic-bezier(0.68, -0.55, 0.265, 1.55) → bouncy flip
- infinite to 3 in bounce → stops after 3 times
Quick Animations Mastery Checklist (2026)
- Use transform, opacity, filter for animations — best performance
- Prefer cubic-bezier() over ease for natural feel
- Keep durations 0.4s–1.2s — too long = annoying
- Use animation-fill-mode: forwards when you want final state to stay
- Add animation-play-state: paused on hover if needed
- Test on mobile — avoid heavy 3D on low-end devices
How does the flip card feel when you hover? That smooth 3D rotation is why animations are everywhere in 2026 design.
Next possible lessons — tell me:
- “10 beautiful micro-interactions using animations”
- “page load animations & scroll-triggered effects”
- “pure CSS loaders & spinners”
- “animation vs transition — decision guide”
- “performance tips for complex animations”
You’ve just learned how to give your websites motion & personality. Chai khatam? Fresh cup lao — let’s keep animating! 🚀 😄
