Logo
Logo
CoursesAboutArchiveCategoriesSearchContact
/
MBlogs

Your go-to resource for programming tutorials, coding tips, and web development insights.

GitHubLinkedIn

Explore

  • Archive
  • Categories
  • Courses
  • Search

Company

  • About
  • Contact

Preferences

Theme

© 2026 M-bloging. All rights reserved.

Made with ♥ by Muhaymin

CSS

11 Articles
Introduction to CSSBCSS Syntax & SelectorsBAdding CSS to HTMLBColors & BackgroundsBCSS Units & ValuesBCSS Comments & OrganizationBCSS SpecificityBThe CSS CascadeBCSS InheritanceBBrowser Defaults & CSS ResetB
All Courses

CSS

11 Articles
Introduction to CSSBCSS Syntax & SelectorsBAdding CSS to HTMLBColors & BackgroundsBCSS Units & ValuesBCSS Comments & OrganizationBCSS SpecificityBThe CSS CascadeBCSS InheritanceBBrowser Defaults & CSS ResetB
All Courses
Courses/CSS
Intermediate11 min read

CSS Keyframe Animations: From Basics to Advanced Techniques

11 min read
380 words
12 sections11 code blocks

CSS Keyframe Animations: From Basics to Advanced Techniques

CSS keyframe animations allow you to create complex, multi-step animations purely with CSS. Unlike transitions which only animate between two states, keyframe animations give you complete control over every step of the animation sequence. This guide takes you from the fundamentals to advanced techniques used in production websites.

Understanding @keyframes

The @keyframes rule defines the stages of an animation. You specify what styles the element should have at various points during the animation sequence. The browser then interpolates between these keyframes to create smooth motion.

CSS
/* Basic @keyframes syntax */
@keyframes slideIn {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* Using percentages for more control */
@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  25% {
    transform: translateY(-30px);
  }
  50% {
    transform: translateY(0);
  }
  75% {
    transform: translateY(-15px);
  }
  100% {
    transform: translateY(0);
  }
}

/* Apply animation to element */
.element {
  animation: slideIn 0.5s ease-out;
}

.bouncing-element {
  animation: bounce 1s ease-in-out infinite;
}

The animation Property Breakdown

The animation shorthand combines multiple properties. Understanding each component gives you precise control over animation behavior.

CSS
/* animation shorthand syntax */
.element {
  animation: name duration timing-function delay iteration-count
             direction fill-mode play-state;
}

/* Full example with all properties */
.complete-animation {
  animation:
    fadeSlide        /* animation-name */
    2s               /* animation-duration */
    ease-in-out      /* animation-timing-function */
    0.5s             /* animation-delay */
    3                /* animation-iteration-count */
    alternate        /* animation-direction */
    forwards         /* animation-fill-mode */
    running;         /* animation-play-state */
}

/* Individual properties for clarity */
.element {
  animation-name: fadeSlide;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-delay: 0.5s;
  animation-iteration-count: 3;
  animation-direction: alternate;
  animation-fill-mode: forwards;
  animation-play-state: running;
}

Animation Timing Functions

Timing functions control the pace of the animation. They determine how intermediate values are calculated between keyframes, creating different feels from mechanical to natural motion.

CSS
/* Built-in timing functions */
.linear    { animation-timing-function: linear; }
.ease      { animation-timing-function: ease; }
.ease-in   { animation-timing-function: ease-in; }
.ease-out  { animation-timing-function: ease-out; }
.ease-in-out { animation-timing-function: ease-in-out; }

/* Custom cubic-bezier curves */
.custom-ease {
  /* cubic-bezier(x1, y1, x2, y2) */
  animation-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
  /* Creates an "overshoot" effect */
}

/* Snappy, energetic motion */
.snappy {
  animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* Smooth deceleration */
.smooth-stop {
  animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}

/* Step functions for frame-by-frame animation */
.sprite-animation {
  animation-timing-function: steps(6);
  /* Jumps through 6 discrete steps */
}

.typewriter {
  animation-timing-function: steps(20, end);
  /* 20 steps, jumps at end of each step */
}

/* Per-keyframe timing */
@keyframes customTiming {
  0% {
    transform: scale(1);
    animation-timing-function: ease-out;
  }
  50% {
    transform: scale(1.5);
    animation-timing-function: ease-in;
  }
  100% {
    transform: scale(1);
  }
}

Animation Direction and Iteration

Control how many times an animation plays and in which direction. These properties are essential for creating looping animations and ping-pong effects.

CSS
/* Iteration count */
.play-once    { animation-iteration-count: 1; }
.play-thrice  { animation-iteration-count: 3; }
.play-forever { animation-iteration-count: infinite; }
.play-partial { animation-iteration-count: 2.5; } /* Stops halfway through 3rd */

/* Animation direction */
.normal    { animation-direction: normal; }    /* 0% → 100% */
.reverse   { animation-direction: reverse; }   /* 100% → 0% */
.alternate { animation-direction: alternate; } /* 0% → 100% → 0% → ... */
.alt-rev   { animation-direction: alternate-reverse; } /* 100% → 0% → 100% → ... */

/* Practical example: Pulsing element */
@keyframes pulse {
  from {
    transform: scale(1);
    opacity: 1;
  }
  to {
    transform: scale(1.1);
    opacity: 0.8;
  }
}

.pulsing {
  animation: pulse 0.5s ease-in-out infinite alternate;
  /* Smoothly scales up and down forever */
}

Fill Modes: Before and After Animation

animation-fill-mode controls what styles apply before the animation starts and after it ends. This is crucial for preventing jarring style changes when animations complete.

CSS
/* Fill mode values */
.none {
  animation-fill-mode: none;
  /* Element reverts to original styles before/after animation */
}

.forwards {
  animation-fill-mode: forwards;
  /* Element keeps the final keyframe styles after animation ends */
}

.backwards {
  animation-fill-mode: backwards;
  /* Element has first keyframe styles during delay period */
}

.both {
  animation-fill-mode: both;
  /* Combines forwards and backwards behavior */
}

/* Practical example: Fade in and stay visible */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-in-element {
  opacity: 0; /* Initial state */
  animation: fadeIn 0.5s ease-out 0.3s forwards;
  /*
    - Starts invisible (opacity: 0 from element style)
    - Waits 0.3s (delay)
    - Animates to visible
    - STAYS visible (forwards)
  */
}

/* Without forwards, it would jump back to opacity: 0 after animation */

/* Using backwards for delayed animations */
.delayed-fade {
  animation: fadeIn 0.5s ease-out 1s backwards;
  /*
    - Immediately applies from keyframe (opacity: 0, translateY: 20px)
    - Waits 1s
    - Animates to final state
    - Reverts to original styles (if no forwards)
  */
}

Multiple Animations

Elements can have multiple animations running simultaneously. Separate them with commas in the animation property or use multiple animation-name values.

CSS
/* Multiple animations on one element */
@keyframes moveRight {
  to { transform: translateX(200px); }
}

@keyframes fadeOut {
  to { opacity: 0; }
}

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

/* Apply multiple animations */
.multi-animated {
  animation:
    moveRight 2s ease-out forwards,
    fadeOut 2s ease-in 1s forwards;
  /* Moves right while fading out (fade starts 1s later) */
}

/* Combining transform animations requires one keyframe */
@keyframes moveAndSpin {
  to {
    transform: translateX(200px) rotate(360deg);
  }
}

/* Staggered entrance animations */
.card:nth-child(1) { animation: fadeIn 0.5s ease-out 0.0s both; }
.card:nth-child(2) { animation: fadeIn 0.5s ease-out 0.1s both; }
.card:nth-child(3) { animation: fadeIn 0.5s ease-out 0.2s both; }
.card:nth-child(4) { animation: fadeIn 0.5s ease-out 0.3s both; }

/* Using CSS custom properties for dynamic delays */
.card {
  animation: fadeIn 0.5s ease-out both;
  animation-delay: calc(var(--index) * 0.1s);
}

/* In HTML: style="--index: 0" style="--index: 1" etc. */

Controlling Animation with play-state

The animation-play-state property lets you pause and resume animations. This is perfect for hover interactions, user controls, or conditional animations.

CSS
/* Pause/resume with play-state */
.animated-element {
  animation: spin 2s linear infinite;
  animation-play-state: running; /* default */
}

.animated-element:hover {
  animation-play-state: paused;
}

/* Pause all animations in a container */
.container:hover .animated-element {
  animation-play-state: paused;
}

/* JavaScript control */
.paused {
  animation-play-state: paused;
}

/* Toggle with checkbox (pure CSS) */
#pause-toggle:checked ~ .animated-element {
  animation-play-state: paused;
}

/* Pause on reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation-play-state: paused;
    /* Or better: animation: none; */
  }
}

Complex Animation Sequences

By carefully crafting keyframe percentages, you can create sophisticated animation sequences with pauses, speed changes, and multiple phases.

CSS
/* Animation with built-in pause */
@keyframes moveWithPause {
  0% {
    transform: translateX(0);
  }
  40% {
    transform: translateX(200px);
  }
  60% {
    transform: translateX(200px); /* Pause here */
  }
  100% {
    transform: translateX(0);
  }
}

/* Multi-phase animation */
@keyframes complexSequence {
  0% {
    transform: scale(1) rotate(0deg);
    opacity: 1;
  }
  25% {
    transform: scale(1.2) rotate(90deg);
    opacity: 1;
  }
  50% {
    transform: scale(0.8) rotate(180deg);
    opacity: 0.5;
  }
  75% {
    transform: scale(1.1) rotate(270deg);
    opacity: 0.8;
  }
  100% {
    transform: scale(1) rotate(360deg);
    opacity: 1;
  }
}

/* Loading spinner with varying speed */
@keyframes spinnerPulse {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(180deg);
  }
  50% {
    transform: rotate(180deg); /* Pause at halfway */
  }
  75% {
    transform: rotate(360deg);
  }
  100% {
    transform: rotate(360deg); /* Pause at complete */
  }
}

/* Typewriter effect */
@keyframes typewriter {
  from { width: 0; }
  to { width: 100%; }
}

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

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

Animation Events in CSS and JavaScript

JavaScript can listen for animation events, allowing you to chain animations, trigger actions on completion, or create complex orchestrated sequences.

CSS
/* JavaScript animation events */
const element = document.querySelector('.animated');

// Animation starts
element.addEventListener('animationstart', (e) => {
  console.log('Animation started:', e.animationName);
});

// Each iteration completes (for infinite/multiple iterations)
element.addEventListener('animationiteration', (e) => {
  console.log('Animation iteration:', e.elapsedTime);
});

// Animation ends
element.addEventListener('animationend', (e) => {
  console.log('Animation ended:', e.animationName);
  element.classList.add('animation-complete');
});

/* Chaining animations */
element.addEventListener('animationend', () => {
  element.classList.remove('first-animation');
  element.classList.add('second-animation');
});

/* CSS for the sequence */
.first-animation {
  animation: slideIn 0.5s ease-out forwards;
}

.second-animation {
  animation: pulse 1s ease-in-out 3;
}

/* Trigger animation on demand */
function triggerAnimation() {
  element.classList.remove('animate');
  void element.offsetWidth; /* Force reflow */
  element.classList.add('animate');
}

Performance Optimization

Not all CSS properties animate efficiently. For smooth 60fps animations, stick to transform and opacity, which can be hardware-accelerated. Animating layout properties like width, height, or margin causes expensive repaints.

CSS
/* ✓ PERFORMANT: transform and opacity */
@keyframes optimized {
  from {
    transform: translateX(0) scale(1);
    opacity: 0.5;
  }
  to {
    transform: translateX(100px) scale(1.2);
    opacity: 1;
  }
}

/* ✗ SLOW: Layout-triggering properties */
@keyframes slow {
  from {
    width: 100px;
    height: 100px;
    margin-left: 0;
  }
  to {
    width: 200px;
    height: 200px;
    margin-left: 100px;
  }
}

/* Better: Use transform instead of changing dimensions */
@keyframes growOptimized {
  from {
    transform: scale(1);
  }
  to {
    transform: scale(2);
  }
}

/* Promote to own layer for complex animations */
.animated-element {
  will-change: transform, opacity;
  /* Or: transform: translateZ(0); */
}

/* Clean up will-change after animation */
.animated-element.animation-complete {
  will-change: auto;
}

/* Reduce motion for accessibility */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Practical Animation Patterns

CSS
/* Pattern: Skeleton loading */
@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

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

/* Pattern: Notification badge */
@keyframes notificationPop {
  0% {
    transform: scale(0);
    opacity: 0;
  }
  50% {
    transform: scale(1.3);
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

.badge {
  animation: notificationPop 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}

/* Pattern: Floating action button */
@keyframes float {
  0%, 100% {
    transform: translateY(0);
    box-shadow: 0 5px 15px rgba(0,0,0,0.2);
  }
  50% {
    transform: translateY(-10px);
    box-shadow: 0 15px 25px rgba(0,0,0,0.15);
  }
}

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

/* Pattern: Page transition */
@keyframes pageEnter {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.page {
  animation: pageEnter 0.4s ease-out;
}

Summary

CSS keyframe animations provide powerful tools for creating engaging user experiences. Start with simple animations and gradually incorporate advanced techniques. Remember to prioritize performance by animating transform and opacity, respect user preferences with prefers-reduced-motion, and use animation events for complex sequences. With practice, you'll be creating smooth, professional animations that enhance your web applications.

Browse All Courses
On this page
0/12