🎬 CSS3 Animations

Create complex, multi-step animations with @keyframes and animation properties

← Back to Content ← Back to Home

🎯 What are CSS Animations?

CSS Animations allow you to create complex, multi-step animations without JavaScript. Unlike transitions which require a trigger (like hover), animations can run automatically, loop infinitely, and have multiple intermediate steps defined with @keyframes.

Animation Capabilities:

  • ✅ Create multi-step animations with @keyframes
  • ✅ Run animations automatically on page load
  • ✅ Loop animations infinitely or specific times
  • ✅ Control animation direction and fill modes
  • ✅ Pause and play animations dynamically
  • ✅ Chain multiple animations together

Transitions vs Animations:

Feature Transitions Animations
Trigger Requires state change Automatic or triggered
Steps 2 (start → end) Multiple keyframes
Loop No Yes
Control Limited Full control

🎞️ Creating @keyframes

@keyframes define the animation sequence with multiple steps.

Basic @keyframes Syntax:

/* Using from and to */
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* Using percentages */
@keyframes slide {
    0% {
        transform: translateX(0);
    }
    50% {
        transform: translateX(100px);
    }
    100% {
        transform: translateX(0);
    }
}

/* Multiple properties */
@keyframes scaleAndRotate {
    0% {
        transform: scale(1) rotate(0deg);
        opacity: 1;
    }
    50% {
        transform: scale(1.5) rotate(180deg);
        opacity: 0.5;
    }
    100% {
        transform: scale(1) rotate(360deg);
        opacity: 1;
    }
}

Multiple Keyframe Steps:

/* Complex animation with many steps */
@keyframes bounce {
    0%, 100% {
        transform: translateY(0);
    }
    25% {
        transform: translateY(-30px);
    }
    50% {
        transform: translateY(-15px);
    }
    75% {
        transform: translateY(-5px);
    }
}

/* Color progression */
@keyframes rainbow {
    0% { background-color: red; }
    16% { background-color: orange; }
    33% { background-color: yellow; }
    50% { background-color: green; }
    66% { background-color: blue; }
    83% { background-color: indigo; }
    100% { background-color: violet; }
}

⚙️ Animation Properties

1. animation-name:

/* Reference the @keyframes name */
.element {
    animation-name: fadeIn;
    animation-name: bounce;
    animation-name: slideIn;
}

2. animation-duration:

/* How long the animation takes */
.element {
    animation-duration: 1s;      /* 1 second */
    animation-duration: 500ms;   /* 500 milliseconds */
    animation-duration: 2.5s;    /* 2.5 seconds */
}

3. animation-timing-function:

/* Speed curve of animation */
.element {
    animation-timing-function: ease;        /* Default */
    animation-timing-function: linear;      /* Constant */
    animation-timing-function: ease-in;     /* Slow start */
    animation-timing-function: ease-out;    /* Slow end */
    animation-timing-function: ease-in-out; /* Slow start & end */
    animation-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

4. animation-delay:

/* Delay before animation starts */
.element {
    animation-delay: 0s;      /* No delay */
    animation-delay: 0.5s;    /* 500ms delay */
    animation-delay: 1s;      /* 1 second delay */
    animation-delay: -0.5s;   /* Start partway through */
}

5. animation-iteration-count:

/* How many times to repeat */
.element {
    animation-iteration-count: 1;        /* Once (default) */
    animation-iteration-count: 3;        /* 3 times */
    animation-iteration-count: infinite; /* Forever */
}

6. animation-direction:

/* Direction of animation */
.element {
    animation-direction: normal;            /* 0% → 100% */
    animation-direction: reverse;           /* 100% → 0% */
    animation-direction: alternate;         /* 0% → 100% → 0% → 100% */
    animation-direction: alternate-reverse; /* 100% → 0% → 100% → 0% */
}

7. animation-fill-mode:

/* Style before/after animation */
.element {
    animation-fill-mode: none;      /* Default - no style applied */
    animation-fill-mode: forwards;  /* Keep final keyframe styles */
    animation-fill-mode: backwards; /* Apply first keyframe before start */
    animation-fill-mode: both;      /* Apply both forwards & backwards */
}

8. animation-play-state:

/* Control play/pause */
.element {
    animation-play-state: running; /* Default */
    animation-play-state: paused;  /* Pause animation */
}

/* Pause on hover */
.element:hover {
    animation-play-state: paused;
}

✍️ Animation Shorthand

Combine all animation properties in one declaration.

/* Shorthand syntax */
/* name | duration | timing-function | delay | iteration | direction | fill-mode | play-state */

.element {
    animation: fadeIn 1s ease 0s 1 normal forwards running;
}

/* Simplified (common pattern) */
.element {
    animation: slideIn 0.5s ease-out;
}

/* Infinite loop */
.element {
    animation: spin 2s linear infinite;
}

/* With delay */
.element {
    animation: bounce 1s ease 0.5s;
}

/* Multiple animations (comma-separated) */
.element {
    animation: fadeIn 1s ease,
               slideUp 1s ease 0.5s,
               bounce 2s ease 1s infinite;
}

Common Shorthand Patterns:

animation: name 1s; animation: name 2s infinite; animation: name 1s ease-in-out forwards; animation: name 0.5s ease 0.3s;

🎨 Live Animation Examples

Bounce

Spin

Pulse

Shake

🌟 Popular Animation Patterns

1. Loading Spinner:

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

.loader {
    width: 50px;
    height: 50px;
    border: 5px solid #f3f3f3;
    border-top: 5px solid #3498db;
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

2. Fade In:

@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.fade-in {
    animation: fadeIn 0.6s ease-out forwards;
}

3. Bounce In:

@keyframes bounceIn {
    0% {
        transform: scale(0);
        opacity: 0;
    }
    50% {
        transform: scale(1.2);
        opacity: 1;
    }
    100% {
        transform: scale(1);
    }
}

.bounce-in {
    animation: bounceIn 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

4. Slide In:

@keyframes slideInLeft {
    from {
        transform: translateX(-100%);
        opacity: 0;
    }
    to {
        transform: translateX(0);
        opacity: 1;
    }
}

.slide-in {
    animation: slideInLeft 0.5s ease-out forwards;
}

5. Pulse Effect:

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

.pulse {
    animation: pulse 2s ease-in-out infinite;
}

6. Shake Effect:

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
    20%, 40%, 60%, 80% { transform: translateX(10px); }
}

.shake {
    animation: shake 0.5s ease;
}

7. Typing Effect:

@keyframes typing {
    from { width: 0; }
    to { width: 100%; }
}

@keyframes blink {
    50% { border-color: transparent; }
}

.typewriter {
    width: 0;
    overflow: hidden;
    border-right: 2px solid;
    white-space: nowrap;
    animation: typing 3s steps(40) forwards,
               blink 0.75s step-end infinite;
}

8. Floating Effect:

@keyframes float {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-20px);
    }
}

.floating {
    animation: float 3s ease-in-out infinite;
}

💼 Practical Real-World Examples

Example 1: Notification Badge:

@keyframes ring {
    0%, 100% { transform: rotate(0deg); }
    10%, 30% { transform: rotate(-10deg); }
    20%, 40% { transform: rotate(10deg); }
}

.notification-badge {
    position: relative;
}

.notification-badge::after {
    content: "3";
    position: absolute;
    top: -8px;
    right: -8px;
    background: red;
    color: white;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    animation: ring 2s ease infinite;
}

Example 2: Progress Bar:

@keyframes progress {
    from { width: 0; }
    to { width: 100%; }
}

.progress-bar {
    height: 20px;
    background: #f3f3f3;
    border-radius: 10px;
    overflow: hidden;
}

.progress-bar::after {
    content: "";
    display: block;
    height: 100%;
    background: linear-gradient(90deg, #667eea, #764ba2);
    animation: progress 2s ease-out forwards;
}

Example 3: Skeleton Loading:

@keyframes shimmer {
    0% {
        background-position: -1000px 0;
    }
    100% {
        background-position: 1000px 0;
    }
}

.skeleton {
    background: linear-gradient(
        90deg,
        #f0f0f0 25%,
        #e0e0e0 50%,
        #f0f0f0 75%
    );
    background-size: 1000px 100%;
    animation: shimmer 2s infinite;
}

Example 4: Modal Entrance:

@keyframes modalSlideDown {
    from {
        transform: translateY(-100px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.modal {
    animation: modalSlideDown 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

Example 5: Attention Seeker:

@keyframes heartbeat {
    0%, 100% { transform: scale(1); }
    14% { transform: scale(1.3); }
    28% { transform: scale(1); }
    42% { transform: scale(1.3); }
    70% { transform: scale(1); }
}

.heartbeat {
    animation: heartbeat 1.5s ease-in-out infinite;
}

🚀 Advanced Animation Techniques

Staggered Animations:

/* Delay each item progressively */
.list-item {
    animation: slideIn 0.5s ease-out backwards;
}

.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; }
.list-item:nth-child(4) { animation-delay: 0.4s; }

/* Or use calculated delay */
.list-item:nth-child(n) {
    animation-delay: calc(0.1s * var(--i));
}

Animation Chaining:

/* Run animations in sequence */
.element {
    animation: 
        fadeIn 0.5s ease-out,
        slideUp 0.5s ease-out 0.5s,
        bounce 0.5s ease-out 1s;
}

JavaScript Control:

// Add animation class
element.classList.add('animated');

// Listen for animation end
element.addEventListener('animationend', () => {
    console.log('Animation completed!');
    element.classList.remove('animated');
});

// Listen for animation iteration
element.addEventListener('animationiteration', () => {
    console.log('Animation looped!');
});

Custom Properties in Animations:

/* Use CSS variables */
:root {
    --animation-duration: 2s;
    --animation-color: #3498db;
}

@keyframes colorPulse {
    0%, 100% { background: var(--animation-color); }
    50% { background: transparent; }
}

.element {
    animation: colorPulse var(--animation-duration) infinite;
}

⚡ Performance Best Practices

Optimize Animations:

  • ✅ Animate transform and opacity (GPU-accelerated)
  • ✅ Use will-change for complex animations (sparingly)
  • ✅ Avoid animating layout properties (width, height, margin)
  • ✅ Use animation-play-state to pause off-screen animations
  • ✅ Reduce animation complexity on mobile devices
  • ⚠️ Don't animate too many elements simultaneously
  • ⚠️ Avoid using "all" in animation properties
/* ✅ Good Performance */
@keyframes slide {
    from { transform: translateX(0); }
    to { transform: translateX(100px); }
}

/* ❌ Poor Performance */
@keyframes slide {
    from { left: 0; }
    to { left: 100px; }
}

/* Use will-change for complex animations */
.complex-animation {
    will-change: transform, opacity;
    animation: complexMove 2s ease;
}

/* Remove will-change after animation */
.complex-animation.done {
    will-change: auto;
}

♿ Accessibility Considerations

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
    }
}

/* Or disable completely */
@media (prefers-reduced-motion: reduce) {
    * {
        animation: none !important;
    }
}

/* Provide alternative for essential animations */
@media (prefers-reduced-motion: reduce) {
    .loading {
        animation: none;
    }
    .loading::after {
        content: "Loading...";
    }
}

📝 Test Your Knowledge - MCQ

Q1: What is the correct syntax for defining keyframes?

Q2: Which value makes an animation repeat forever?

Q3: What does animation-fill-mode: forwards do?

Q4: Which direction value makes an animation alternate back and forth?

Q5: What are the best properties to animate for performance?

💪 Practice Questions

  1. Create a bouncing ball animation using @keyframes.
  2. Build a loading spinner that rotates infinitely.
  3. Create a fade-in animation that keeps final styles after completion.
  4. Make a pulsing button animation that repeats forever.
  5. Build a slide-in animation for menu items with staggered delays.
  6. Create a shake animation that plays once on error.
  7. Design a skeleton loading animation with a shimmer effect.
  8. Build a typewriter effect using steps timing function.

📌 Summary

  • @keyframes: Define animation sequences with multiple steps
  • animation-name: References the @keyframes to use
  • animation-duration: How long the animation takes (required)
  • animation-timing-function: Speed curve (ease, linear, etc.)
  • animation-iteration-count: Number of times to repeat (1, 3, infinite)
  • animation-direction: normal, reverse, alternate, alternate-reverse
  • animation-fill-mode: forwards, backwards, both (styles before/after)
  • Shorthand: animation: name duration timing delay iteration direction fill-mode
  • Performance: Use transform and opacity for GPU acceleration

🔑 Key Takeaways

🎬 Multi-Step Control

Animations provide precise control over multiple keyframe steps, unlike transitions which only have start and end states.

🔄 Infinite Loops

Use animation-iteration-count: infinite for continuous animations like loading spinners and pulsing effects.

⚡ Performance Matters

Always animate transform and opacity for best performance. Avoid animating layout properties like width, height, or position.

♿ Accessibility First

Respect prefers-reduced-motion to ensure animations don't cause discomfort for users with motion sensitivity.

← Back to Content ← Back to Home