CSS Animations & Transitions: Complete Guide to Web Motion Design

CSS

CSS Animations & Transitions: Complete Guide to Web Motion Design
Master CSS Animations and Transitions - keyframes, transforms, timing functions, and advanced animation effects for engaging web experiences.
#CSS#Animations#Transitions#Keyframes#Transform#Motion#Effects

CSS Animations & Transitions: Complete Guide to Web Motion Design

Professional Guide by Alaa Amer – Expert Web Developer & Designer

CSS Animations bring life to web interfaces. Learn how to create smooth, engaging motion effects that enhance user experience.


1️⃣ CSS Transitions Basics

Understanding Transitions

/* Basic transition syntax */
.transition-example {
  /* Properties to animate */
  background-color: #3498db;
  transform: scale(1);
  opacity: 1;

  /* Transition configuration */
  transition-property: all; /* which properties to animate */
  transition-duration: 0.3s; /* animation duration */
  transition-timing-function: ease; /* animation curve */
  transition-delay: 0s; /* delay before starting */

  /* Shorthand syntax */
  transition: all 0.3s ease 0s;
}

.transition-example:hover {
  background-color: #e74c3c;
  transform: scale(1.1);
  opacity: 0.8;
}

/* Multiple property transitions */
.multi-transition {
  background: #2ecc71;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

  /* Different transitions for different properties */
  transition:
    background-color 0.3s ease,
    transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55),
    box-shadow 0.2s ease-out;
}

.multi-transition:hover {
  background: #27ae60;
  transform: translateY(-5px) rotate(2deg);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}

2️⃣ Timing Functions and Easing

/* Built-in timing functions */
.timing-examples {
  transition-duration: 0.5s;
}

.linear {
  transition-timing-function: linear;
}
.ease {
  transition-timing-function: ease;
}
.ease-in {
  transition-timing-function: ease-in;
}
.ease-out {
  transition-timing-function: ease-out;
}
.ease-in-out {
  transition-timing-function: ease-in-out;
}

/* Custom cubic-bezier curves */
.custom-ease-1 {
  transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.custom-ease-2 {
  transition-timing-function: cubic-bezier(
    0.68,
    -0.55,
    0.265,
    1.55
  ); /* bouncy */
}
.custom-ease-3 {
  transition-timing-function: cubic-bezier(
    0.95,
    0.05,
    0.795,
    0.035
  ); /* dramatic */
}

/* Steps timing function */
.steps-animation {
  transition: transform 1s steps(4, end);
}

.steps-animation:hover {
  transform: translateX(200px);
  /* Animation will happen in 4 discrete steps */
}

/* Practical button transitions */
.button {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;

  transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
}

.button::before {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.2),
    transparent
  );
  transition: left 0.5s ease;
}

.button:hover {
  transform: translateY(-2px);
  box-shadow: 0 7px 14px rgba(102, 126, 234, 0.4);
}

.button:hover::before {
  left: 100%;
}

.button:active {
  transform: translateY(0);
  transition-duration: 0.1s;
}

3️⃣ CSS Keyframe Animations

/* Basic keyframe syntax */
@keyframes slideInFromLeft {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }
  100% {
    transform: translateX(0);
    opacity: 1;
  }
}

/* Using the animation */
.slide-in {
  animation-name: slideInFromLeft;
  animation-duration: 0.8s;
  animation-timing-function: ease-out;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: both;
  animation-play-state: running;

  /* Shorthand syntax */
  /* animation: slideInFromLeft 0.8s ease-out both; */
}

/* Complex multi-step animation */
@keyframes complexMove {
  0% {
    transform: translateX(0) rotate(0deg);
    background: #3498db;
    border-radius: 4px;
  }
  25% {
    transform: translateX(100px) rotate(90deg);
    background: #e74c3c;
    border-radius: 50%;
  }
  50% {
    transform: translateX(100px) translateY(-50px) rotate(180deg);
    background: #2ecc71;
    border-radius: 4px;
  }
  75% {
    transform: translateX(0) translateY(-50px) rotate(270deg);
    background: #f39c12;
    border-radius: 50%;
  }
  100% {
    transform: translateX(0) translateY(0) rotate(360deg);
    background: #9b59b6;
    border-radius: 4px;
  }
}

.complex-animation {
  width: 50px;
  height: 50px;
  animation: complexMove 3s ease-in-out infinite;
}

/* Practical animations library */

/* Fade animations */
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

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

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

/* Scale animations */
@keyframes zoomIn {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

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

/* Bounce animation */
@keyframes bounce {
  0%,
  20%,
  53%,
  80%,
  100% {
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    transform: translate3d(0, 0, 0);
  }
  40%,
  43% {
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    transform: translate3d(0, -30px, 0);
  }
  70% {
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    transform: translate3d(0, -15px, 0);
  }
  90% {
    transform: translate3d(0, -4px, 0);
  }
}

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

/* Rotation animations */
@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes flip {
  from {
    transform: perspective(400px) rotateY(0);
  }
  to {
    transform: perspective(400px) rotateY(180deg);
  }
}

4️⃣ Advanced Animation Effects

/* Loading animations */
@keyframes spinner {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spinner 1s linear infinite;
}

/* Dots loading animation */
@keyframes dotsBounce {
  0%,
  80%,
  100% {
    transform: scale(0);
  }
  40% {
    transform: scale(1);
  }
}

.loading-dots {
  display: inline-block;
  position: relative;
  width: 80px;
  height: 80px;
}

.loading-dots div {
  position: absolute;
  top: 33px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #3498db;
  animation: dotsBounce 1.4s infinite ease-in-out both;
}

.loading-dots div:nth-child(1) {
  left: 8px;
  animation-delay: -0.32s;
}
.loading-dots div:nth-child(2) {
  left: 32px;
  animation-delay: -0.16s;
}
.loading-dots div:nth-child(3) {
  left: 56px;
  animation-delay: 0s;
}

/* Typing animation */
@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}

@keyframes blinkCaret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: #333;
  }
}

.typewriter {
  overflow: hidden;
  border-right: 2px solid #333;
  white-space: nowrap;
  margin: 0 auto;
  animation:
    typing 3.5s steps(40, end),
    blinkCaret 0.75s step-end infinite;
}

/* Floating animation */
@keyframes float {
  0% {
    transform: translateY(0px);
  }
  50% {
    transform: translateY(-20px);
  }
  100% {
    transform: translateY(0px);
  }
}

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

/* Morphing button */
.morph-button {
  background: #3498db;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 25px;
  cursor: pointer;
  transition: all 0.3s ease;
  overflow: hidden;
  position: relative;
}

.morph-button:hover {
  border-radius: 4px;
  padding: 12px 40px;
  background: #2980b9;
}

.morph-button::after {
  content: "→";
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%) translateX(20px);
  opacity: 0;
  transition: all 0.3s ease;
}

.morph-button:hover::after {
  transform: translateY(-50%) translateX(0);
  opacity: 1;
}

/* Staggered animations */
.stagger-container {
  display: flex;
  gap: 10px;
}

.stagger-item {
  width: 20px;
  height: 20px;
  background: #e74c3c;
  border-radius: 50%;
  animation: bounce 0.6s ease-in-out infinite alternate;
}

.stagger-item:nth-child(1) {
  animation-delay: 0s;
}
.stagger-item:nth-child(2) {
  animation-delay: 0.1s;
}
.stagger-item:nth-child(3) {
  animation-delay: 0.2s;
}
.stagger-item:nth-child(4) {
  animation-delay: 0.3s;
}
.stagger-item:nth-child(5) {
  animation-delay: 0.4s;
}

5️⃣ Transform Property Deep Dive

/* 2D Transforms */
.transform-examples {
  /* Translation */
  transform: translateX(50px); /* Move horizontally */
  transform: translateY(-20px); /* Move vertically */
  transform: translate(50px, -20px); /* Move both directions */

  /* Scaling */
  transform: scaleX(1.5); /* Scale horizontally */
  transform: scaleY(0.8); /* Scale vertically */
  transform: scale(1.2); /* Scale uniformly */
  transform: scale(1.5, 0.8); /* Scale both directions */

  /* Rotation */
  transform: rotate(45deg); /* Rotate clockwise */
  transform: rotate(-30deg); /* Rotate counterclockwise */

  /* Skewing */
  transform: skewX(20deg); /* Skew horizontally */
  transform: skewY(-10deg); /* Skew vertically */
  transform: skew(20deg, -10deg); /* Skew both directions */

  /* Combined transforms */
  transform: translate(50px, 100px) rotate(45deg) scale(1.2);
}

/* 3D Transforms */
.transform-3d {
  /* 3D Translation */
  transform: translateZ(50px); /* Move in Z axis */
  transform: translate3d(50px, 100px, 25px); /* 3D translation */

  /* 3D Rotation */
  transform: rotateX(45deg); /* Rotate around X axis */
  transform: rotateY(60deg); /* Rotate around Y axis */
  transform: rotateZ(30deg); /* Rotate around Z axis */
  transform: rotate3d(1, 1, 0, 45deg); /* Rotate around custom axis */

  /* 3D Scaling */
  transform: scaleZ(2); /* Scale in Z direction */
  transform: scale3d(1.5, 1.2, 2); /* 3D scaling */

  /* Perspective */
  perspective: 1000px; /* Set 3D perspective */
  transform-style: preserve-3d; /* Preserve 3D for children */
}

/* Transform origin */
.transform-origin-examples {
  /* Default origin is center center */
  transform-origin: center center;

  /* Other origin points */
  transform-origin: top left;
  transform-origin: bottom right;
  transform-origin: 50% 25%;
  transform-origin: 10px 20px;

  /* 3D origin */
  transform-origin: center center 50px;
}

/* Practical 3D card flip */
.flip-card {
  background-color: transparent;
  width: 300px;
  height: 200px;
  perspective: 1000px;
}

.flip-card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  text-align: center;
  transition: transform 0.6s;
  transform-style: preserve-3d;
}

.flip-card:hover .flip-card-inner {
  transform: rotateY(180deg);
}

.flip-card-front,
.flip-card-back {
  position: absolute;
  width: 100%;
  height: 100%;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  color: white;
}

.flip-card-front {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.flip-card-back {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  transform: rotateY(180deg);
}

6️⃣ Animation Performance and Best Practices

/* Hardware acceleration */
.gpu-accelerated {
  /* These properties trigger hardware acceleration */
  transform: translateZ(0);
  will-change: transform, opacity;

  /* Or use transform3d for the same effect */
  transform: translate3d(0, 0, 0);
}

/* Optimized animations - use transform and opacity */
.optimized-animation {
  /* ✅ Good - animates well */
  transition:
    transform 0.3s ease,
    opacity 0.3s ease;
}

.optimized-animation:hover {
  transform: translateY(-5px) scale(1.02);
  opacity: 0.9;
}

/* Use will-change for complex animations */
.complex-hover-card {
  will-change: transform;
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.complex-hover-card:hover {
  transform: translateY(-8px) rotateX(15deg) rotateY(5deg);
}

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

/* Reduced motion accessibility */
@media (prefers-reduced-motion: reduce) {
  .respectful-animation {
    animation: none;
    transition: none;
  }

  /* Provide alternative static states */
  .respectful-animation:hover {
    background-color: #e3f2fd;
    border-color: #2196f3;
  }
}

7️⃣ Complete Interactive Dashboard Project

This project demonstrates all the animation concepts in a practical, modern dashboard interface with comprehensive animations and interactions.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Animated Dashboard - CSS Animations Showcase</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family:
          -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        padding: 20px;
      }

      .dashboard {
        max-width: 1200px;
        margin: 0 auto;
        animation: fadeInUp 1s ease both;
      }

      .header {
        background: rgba(255, 255, 255, 0.95);
        backdrop-filter: blur(10px);
        border-radius: 15px;
        padding: 25px;
        margin-bottom: 30px;
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
      }

      .header h1 {
        color: #333;
        font-size: 2rem;
        margin-bottom: 10px;
        animation: slideInFromLeft 0.8s ease 0.2s both;
      }

      .header p {
        color: #666;
        animation: slideInFromLeft 0.8s ease 0.4s both;
      }

      .stats-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
        gap: 25px;
        margin-bottom: 30px;
      }

      .stat-card {
        background: rgba(255, 255, 255, 0.95);
        backdrop-filter: blur(10px);
        border-radius: 15px;
        padding: 25px;
        text-align: center;
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        position: relative;
        overflow: hidden;
        animation: zoomIn 0.6s ease both;
      }

      .stat-card:nth-child(1) {
        animation-delay: 0.1s;
      }
      .stat-card:nth-child(2) {
        animation-delay: 0.2s;
      }
      .stat-card:nth-child(3) {
        animation-delay: 0.3s;
      }
      .stat-card:nth-child(4) {
        animation-delay: 0.4s;
      }

      .stat-card::before {
        content: "";
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.4),
          transparent
        );
        transition: left 0.6s ease;
      }

      .stat-card:hover {
        transform: translateY(-10px) scale(1.02);
        box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
      }

      .stat-card:hover::before {
        left: 100%;
      }

      .stat-icon {
        width: 60px;
        height: 60px;
        margin: 0 auto 15px;
        background: linear-gradient(135deg, #667eea, #764ba2);
        border-radius: 15px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        color: white;
        animation: pulse 2s infinite;
      }

      .stat-number {
        font-size: 2.5rem;
        font-weight: bold;
        color: #333;
        margin-bottom: 5px;
        animation: countUp 2s ease-in-out;
      }

      .stat-label {
        color: #666;
        font-size: 0.9rem;
        text-transform: uppercase;
        letter-spacing: 1px;
      }

      .floating-action {
        position: fixed;
        bottom: 30px;
        right: 30px;
        width: 60px;
        height: 60px;
        background: linear-gradient(135deg, #667eea, #764ba2);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 24px;
        cursor: pointer;
        box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
        animation: float 3s ease-in-out infinite;
        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      }

      .floating-action:hover {
        transform: scale(1.1);
        box-shadow: 0 12px 40px rgba(102, 126, 234, 0.4);
      }

      /* Keyframe Animations */
      @keyframes fadeInUp {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      @keyframes slideInFromLeft {
        from {
          opacity: 0;
          transform: translateX(-50px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      @keyframes zoomIn {
        from {
          opacity: 0;
          transform: scale(0.3);
        }
        to {
          opacity: 1;
          transform: scale(1);
        }
      }

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

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

      @keyframes countUp {
        from {
          transform: scale(0.5);
          opacity: 0;
        }
        to {
          transform: scale(1);
          opacity: 1;
        }
      }

      /* Responsive Design */
      @media (max-width: 768px) {
        .stats-grid {
          grid-template-columns: 1fr;
        }

        .header h1 {
          font-size: 1.5rem;
        }

        .stat-number {
          font-size: 2rem;
        }
      }

      /* Reduced Motion */
      @media (prefers-reduced-motion: reduce) {
        * {
          animation-duration: 0.01ms !important;
          animation-iteration-count: 1 !important;
          transition-duration: 0.01ms !important;
        }
      }
    </style>
  </head>
  <body>
    <div class="dashboard">
      <!-- Header -->
      <div class="header">
        <h1>Analytics Dashboard</h1>
        <p>Welcome back! Here's what's happening with your projects today.</p>
      </div>

      <!-- Statistics Cards -->
      <div class="stats-grid">
        <div class="stat-card">
          <div class="stat-icon">📊</div>
          <div class="stat-number">15,847</div>
          <div class="stat-label">Total Views</div>
        </div>
        <div class="stat-card">
          <div class="stat-icon">👥</div>
          <div class="stat-number">3,296</div>
          <div class="stat-label">Active Users</div>
        </div>
        <div class="stat-card">
          <div class="stat-icon">💰</div>
          <div class="stat-number">$12,847</div>
          <div class="stat-label">Revenue</div>
        </div>
        <div class="stat-card">
          <div class="stat-icon">📈</div>
          <div class="stat-number">23.5%</div>
          <div class="stat-label">Growth Rate</div>
        </div>
      </div>
    </div>

    <!-- Floating Action Button -->
    <div class="floating-action">+</div>

    <script>
      // Add interactive functionality
      document.addEventListener("DOMContentLoaded", function () {
        // Animate numbers counting up
        const numbers = document.querySelectorAll(".stat-number");
        numbers.forEach((number) => {
          const finalValue = number.textContent.replace(/[^0-9.]/g, "");
          if (!isNaN(finalValue)) {
            animateNumber(number, 0, parseFloat(finalValue), 2000);
          }
        });

        // Add click interactions
        const statCards = document.querySelectorAll(".stat-card");
        statCards.forEach((card) => {
          card.addEventListener("click", function () {
            this.style.animation = "pulse 0.6s ease";
            setTimeout(() => {
              this.style.animation = "";
            }, 600);
          });
        });

        // Floating action button interaction
        const fab = document.querySelector(".floating-action");
        fab.addEventListener("click", function () {
          this.style.animation = "bounce 0.6s ease";
          setTimeout(() => {
            this.style.animation = "float 3s ease-in-out infinite";
          }, 600);
        });
      });

      function animateNumber(element, start, end, duration) {
        const startTime = performance.now();
        const originalText = element.textContent;

        function updateNumber(currentTime) {
          const elapsed = currentTime - startTime;
          const progress = Math.min(elapsed / duration, 1);

          const currentValue = start + (end - start) * easeOutQuart(progress);
          element.textContent = originalText.replace(
            /[0-9.]+/,
            Math.floor(currentValue).toLocaleString()
          );

          if (progress < 1) {
            requestAnimationFrame(updateNumber);
          }
        }

        requestAnimationFrame(updateNumber);
      }

      function easeOutQuart(t) {
        return 1 - Math.pow(1 - t, 4);
      }
    </script>
  </body>
</html>

Summary

In this lesson we learned:

CSS Transitions fundamentalsKeyframe Animations and timing functionsTransform properties and 3D effectsAdvanced animation techniquesPerformance optimization best practicesComplete interactive dashboard project

In the next lesson we'll study CSS Grid Advanced Techniques and Complex Layouts.

📩 Need help with Animations?

aboutservicesprojectsBlogscontact