⚡ Phase 3 🔴 Intermediate ⏱️ 45 min ✨ 5 sections

Transitions & Animations

🎞️ transition · @keyframes · transform · animation shorthand
🏆 Lesson 10 of 12
Lesson progress0%
Motion is what separates a static page from a living interface. CSS gives you two tools: transitions for state changes (hover, focus, active) and @keyframes animations for complex, looping, or auto-playing motion. In this lesson you'll master both — plus transform functions, timing functions, and the golden rules of performance-safe animation.

The transition Property

A transition smoothly animates a property when it changes value — usually on :hover or :focus. The syntax is: transition: property duration timing-function delay.

transition syntax and examples
CSS
/* Single property */
.btn { transition: background-color 0.3s ease; }

/* Multiple properties */
.card {
  transition: transform 0.25s ease,
              box-shadow 0.25s ease,
              opacity 0.2s ease;
}

/* All properties (use sparingly — can be slow) */
.el { transition: all 0.3s ease; }

/* With delay */
.tooltip { transition: opacity 0.2s ease 0.1s; }
/*                                         ↑ delay */

/* Practical button example */
.btn {
  background: #2de8c0;
  transform: translateY(0);
  transition: background 0.2s ease, transform 0.15s ease;
}
.btn:hover {
  background: #0d9488;
  transform: translateY(-3px);
}
🎨
hover me
color + lift
hover me
rotate + morph
🚀
hover me
spring scale
💫
hover me
glow + lift

Timing Functions

The timing function controls how speed changes over the duration of a transition or animation. The difference between a cheap-feeling and premium-feeling animation is almost always the timing function.

Timing function reference
CSS
/* Built-in keywords */
transition-timing-function: ease;          /* default — slow, fast, slow */
transition-timing-function: ease-in;       /* slow start */
transition-timing-function: ease-out;      /* slow end — feels natural */
transition-timing-function: ease-in-out;   /* slow both ends */
transition-timing-function: linear;        /* constant speed */

/* cubic-bezier() — full control */
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); /* spring overshoot */
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);     /* Material Design */

/* steps() — for sprite animations */
transition-timing-function: steps(8, end);
ease
slow-fast-slow
ease-in
slow start
ease-out
slow end
ease-in-out
slow both
linear
constant
spring
cubic-bezier

↑ Hover each card to see the easing in action

The transform Property

transform lets you move, scale, rotate, and skew elements without affecting layout. Unlike changing top or margin, transforms are GPU-accelerated — they're fast and don't trigger layout recalculations.

Transform functions
CSS
/* Translate — move */
transform: translateX(20px);     /* move right */
transform: translateY(-10px);    /* move up */
transform: translate(20px, -10px); /* both axes */

/* Scale */
transform: scale(1.2);   /* 20% bigger */
transform: scale(0.8);   /* 20% smaller */
transform: scaleX(1.5); /* stretch horizontally */

/* Rotate */
transform: rotate(45deg);   /* clockwise 45° */
transform: rotate(-90deg);  /* counter-clockwise */

/* Skew */
transform: skewX(15deg);

/* Combine — order matters! */
.card:hover {
  transform: translateY(-8px) scale(1.03) rotate(1deg);
}

/* 3D transforms */
transform: perspective(500px) rotateY(30deg);
🎮 Transform Playground
Adjust the sliders to see transforms in real time
TRANSLATE X (px)
TRANSLATE Y (px)
SCALE
ROTATE (deg)
📦
transform: translateX(0px) translateY(0px) scale(1) rotate(0deg);

@keyframes Animations

While transitions react to state changes, @keyframes animations run automatically — on load, on loop, or triggered by a class. You define waypoints (0%, 50%, 100%) and the browser fills in the motion between them.

@keyframes syntax + animation shorthand
CSS
/* 1. Define the keyframes */
@keyframes fadeSlideIn {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.1); }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* 2. Apply — shorthand: name duration timing iteration direction fill-mode */
.hero-title { animation: fadeSlideIn 0.6s ease-out both; }
.loader     { animation: spin 1s linear infinite; }
.badge      { animation: pulse 2s ease-in-out infinite; }

/* Individual properties */
.el {
  animation-name:            fadeSlideIn;
  animation-duration:        0.6s;
  animation-timing-function: ease-out;
  animation-iteration-count: 1;        /* or infinite */
  animation-direction:       normal;   /* or reverse, alternate */
  animation-fill-mode:       both;     /* keeps end state */
  animation-delay:           0.2s;
}
pulse
💚
spin
bounce
shake
⚠️
ping
Performance rule: only animate these two properties
Animating transform and opacity is free — they're handled entirely by the GPU and never trigger layout. Animating width, height, top, margin, or padding forces the browser to recalculate layout on every frame — this causes jank. Always use transform: translate() instead of changing top/left.

Stagger & Practical Patterns

Some of the most impressive animation effects are simple CSS techniques applied strategically. Staggering delays, hover card lifts, and loading skeletons are patterns you'll use in every real project.

Animation delay stagger — cards appear one by one
CSS + HTML
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: fadeUp 0.5s ease-out both;
}
/* Stagger via nth-child delay */
.card:nth-child(1) { animation-delay: 0.0s; }
.card:nth-child(2) { animation-delay: 0.1s; }
.card:nth-child(3) { animation-delay: 0.2s; }

/* Or with CSS custom properties from JS */
.card { animation-delay: calc(var(--i) * 0.1s); }
Skeleton loading screen
CSS
@keyframes shimmer {
  from { background-position: -200px 0; }
  to   { background-position: calc(200px + 100%) 0; }
}

.skeleton {
  background: linear-gradient(90deg,
    rgba(255,255,255,.03) 0%,
    rgba(255,255,255,.08) 50%,
    rgba(255,255,255,.03) 100%);
  background-size: 200px 100%;
  animation: shimmer 1.5s ease-in-out infinite;
  border-radius: 6px;
}
animation-fill-modeBehavior
noneElement reverts to original styles when animation ends (default)
forwardsElement keeps the end-state styles after animation finishes
backwardsApply from-state during delay period
bothCombines forwards + backwards — almost always what you want
🧠 Knowledge Check
5 questions — master transitions & animations.
1. What's the difference between a transition and an animation?
2. Which two CSS properties should you almost exclusively animate for best performance?
3. What does animation-fill-mode: both do?
4. What does transform: translate(-50%, -50%) do (a classic centering trick)?
5. What is the ease-out timing function best suited for?
🏆
Coding Challenge
Estimated time: 25–35 min
Build an Animated Hero Section

Create a full-viewport hero section with: (1) a title that fades up on load using @keyframes fadeUp, (2) a subtitle that fades up 0.15s later, (3) a CTA button that fades up at 0.3s, (4) a pulsing gradient background blob, (5) a "scroll down" arrow that bounces with @keyframes bounce. Use animation-fill-mode: both on all entrance animations. Bonus: add a hover effect on the button with a transform: scale(1.05) transition.
💡 Show hints
  • Define one @keyframes fadeUp and reuse it on all three elements with different delays
  • For the gradient blob: position:absolute, border-radius:50%, background:radial-gradient(...), animation with scale and opacity
  • Use animation-fill-mode: both so elements are invisible before their delay fires
  • Bounce arrow: @keyframes bounce { 0%,100%{transform:translateY(0)} 50%{transform:translateY(8px)} }
  • Button hover: put transition on the button base, not the :hover rule
🎉
Lesson 10 Complete!
Transitions & Animations mastered! Your interfaces now have life and personality. Next — CSS Variables & Theming for dynamic, maintainable styles.
← Course Home
Phase 3 · Advanced CSSLesson 10 of 12