CSS Loading Animations ⏳

Create beautiful, accessible, and performant loading animations with modern CSS techniques and best practices.

Why Loading Animations Matter

Loading animations provide crucial visual feedback to users, improve perceived performance, and enhance the overall user experience by managing expectations during wait times.

⏱️ Perceived Performance

Make wait times feel shorter with engaging animations

💡 User Feedback

Provide clear indication that work is in progress

🎨 Brand Experience

Reinforce brand identity through consistent design

Basic CSS Loading Animations

Key Concepts:

  • Use @keyframes for complex animations
  • Leverage animation properties for control
  • Create smooth transitions with ease functions
  • Implement skeleton screens for content loading
  • Ensure accessibility with ARIA attributes

Basic Loading Animations Demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Basic CSS Loading Animations</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Inter', sans-serif;
      line-height: 1.6;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      min-height: 100vh;
      padding: 2rem;
    }
    
    .container {
      max-width: 1000px;
      margin: 0 auto;
      background: white;
      border-radius: 20px;
      padding: 3rem;
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    }
    
    h1 {
      color: #2d3748;
      margin-bottom: 2rem;
      text-align: center;
      font-size: 2.5rem;
    }
    
    .loading-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 2rem;
      margin: 2rem 0;
    }
    
    .loading-group {
      padding: 2rem;
      background: #f8fafc;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
    }
    
    .loading-title {
      font-weight: 600;
      color: #2d3748;
      margin-bottom: 1.5rem;
      font-size: 1.2rem;
    }
    
    /* Spinner Loader */
    .spinner {
      width: 50px;
      height: 50px;
      border: 4px solid #e2e8f0;
      border-top: 4px solid #3b82f6;
      border-radius: 50%;
      animation: spin 1s linear infinite;
      margin: 0 auto;
    }
    
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    
    /* Dots Loader */
    .dots-loader {
      display: flex;
      justify-content: center;
      gap: 8px;
    }
    
    .dot {
      width: 12px;
      height: 12px;
      background: #3b82f6;
      border-radius: 50%;
      animation: bounce 1.4s infinite ease-in-out;
    }
    
    .dot:nth-child(1) { animation-delay: -0.32s; }
    .dot:nth-child(2) { animation-delay: -0.16s; }
    
    @keyframes bounce {
      0%, 80%, 100% {
        transform: scale(0);
        opacity: 0.5;
      }
      40% {
        transform: scale(1);
        opacity: 1;
      }
    }
    
    /* Progress Bar */
    .progress-loader {
      width: 100%;
      height: 6px;
      background: #e2e8f0;
      border-radius: 3px;
      overflow: hidden;
      position: relative;
    }
    
    .progress-bar {
      height: 100%;
      background: #3b82f6;
      border-radius: 3px;
      animation: progress 2s ease-in-out infinite;
    }
    
    @keyframes progress {
      0% { transform: translateX(-100%); }
      50% { transform: translateX(0); }
      100% { transform: translateX(100%); }
    }
    
    /* Pulse Loader */
    .pulse-loader {
      width: 50px;
      height: 50px;
      background: #3b82f6;
      border-radius: 50%;
      margin: 0 auto;
      animation: pulse 1.5s ease-in-out infinite;
    }
    
    @keyframes pulse {
      0% {
        transform: scale(0.8);
        opacity: 0.7;
      }
      50% {
        transform: scale(1.2);
        opacity: 1;
      }
      100% {
        transform: scale(0.8);
        opacity: 0.7;
      }
    }
    
    /* Skeleton Loader */
    .skeleton-loader {
      background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
      background-size: 200% 100%;
      animation: skeleton 1.5s infinite;
      border-radius: 8px;
    }
    
    @keyframes skeleton {
      0% { background-position: 200% 0; }
      100% { background-position: -200% 0; }
    }
    
    .skeleton-card {
      width: 100%;
      padding: 1rem;
    }
    
    .skeleton-avatar {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      margin-bottom: 1rem;
    }
    
    .skeleton-line {
      height: 12px;
      margin-bottom: 8px;
      border-radius: 6px;
    }
    
    .skeleton-line.short {
      width: 60%;
    }
    
    /* Color Variants */
    .loader-success .spinner {
      border-top-color: #10b981;
    }
    
    .loader-warning .spinner {
      border-top-color: #f59e0b;
    }
    
    .loader-danger .spinner {
      border-top-color: #ef4444;
    }
    
    .loader-success .dot {
      background: #10b981;
    }
    
    .loader-success .progress-bar {
      background: #10b981;
    }
    
    /* Size Variants */
    .loader-sm .spinner {
      width: 30px;
      height: 30px;
      border-width: 3px;
    }
    
    .loader-lg .spinner {
      width: 70px;
      height: 70px;
      border-width: 5px;
    }
    
    /* Demo Section */
    .demo-section {
      background: #f8fafc;
      padding: 2rem;
      border-radius: 15px;
      margin: 2rem 0;
      border-left: 4px solid #667eea;
    }
    
    .code-example {
      background: #2d3748;
      color: #81e6d9;
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      margin: 1rem 0;
      font-size: 0.9rem;
    }
    
    .demo-controls {
      display: flex;
      gap: 1rem;
      margin: 1rem 0;
      flex-wrap: wrap;
    }
    
    .demo-btn {
      padding: 8px 16px;
      background: #3b82f6;
      color: white;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 0.875rem;
      transition: background 0.2s ease;
    }
    
    .demo-btn:hover {
      background: #2563eb;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>⏳ CSS Loading Animations</h1>
    
    <div class="demo-section">
      <h2>Basic Loading Spinners</h2>
      <div class="code-example">
        /* CSS Spinner */<br>
        .spinner {<br>
        &nbsp;&nbsp;width: 50px;<br>
        &nbsp;&nbsp;height: 50px;<br>
        &nbsp;&nbsp;border: 4px solid #f3f3f3;<br>
        &nbsp;&nbsp;border-top: 4px solid #3498db;<br>
        &nbsp;&nbsp;border-radius: 50%;<br>
        &nbsp;&nbsp;animation: spin 1s linear infinite;<br>
        }
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">Spinner Loader</div>
          <div class="spinner"></div>
          <div class="demo-controls">
            <button class="demo-btn" onclick="toggleAnimation(this.previousElementSibling)">Pause/Resume</button>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Dots Loader</div>
          <div class="dots-loader">
            <div class="dot"></div>
            <div class="dot"></div>
            <div class="dot"></div>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Progress Bar</div>
          <div class="progress-loader">
            <div class="progress-bar"></div>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Pulse Loader</div>
          <div class="pulse-loader"></div>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Color & Size Variants</h2>
      <div class="code-example">
        /* Color and Size Variants */<br>
        Use CSS classes for different states<br>
        Success, warning, and error states<br>
        Small, medium, and large sizes
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">Color States</div>
          <div class="spinner loader-success" style="margin-bottom: 1rem;"></div>
          <div class="spinner loader-warning" style="margin-bottom: 1rem;"></div>
          <div class="spinner loader-danger"></div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Size Variants</div>
          <div class="spinner loader-sm" style="margin-bottom: 1rem;"></div>
          <div class="spinner" style="margin-bottom: 1rem;"></div>
          <div class="spinner loader-lg"></div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Dots Variants</div>
          <div class="dots-loader loader-success" style="margin-bottom: 1rem;">
            <div class="dot"></div>
            <div class="dot"></div>
            <div class="dot"></div>
          </div>
          <div class="dots-loader loader-warning">
            <div class="dot"></div>
            <div class="dot"></div>
            <div class="dot"></div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Skeleton Loading</h2>
      <div class="code-example">
        /* Skeleton Loading */<br>
        .skeleton-loader {<br>
        &nbsp;&nbsp;background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);<br>
        &nbsp;&nbsp;background-size: 200% 100%;<br>
        &nbsp;&nbsp;animation: skeleton 1.5s infinite;<br>
        }
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">Card Skeleton</div>
          <div class="skeleton-card">
            <div class="skeleton-loader skeleton-avatar"></div>
            <div class="skeleton-loader skeleton-line" style="width: 70%;"></div>
            <div class="skeleton-loader skeleton-line short"></div>
            <div class="skeleton-loader skeleton-line" style="height: 80px; margin-top: 1rem;"></div>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">List Skeleton</div>
          <div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
            <div class="skeleton-loader" style="width: 50px; height: 50px; border-radius: 8px;"></div>
            <div style="flex: 1;">
              <div class="skeleton-loader skeleton-line"></div>
              <div class="skeleton-loader skeleton-line short"></div>
            </div>
          </div>
          <div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
            <div class="skeleton-loader" style="width: 50px; height: 50px; border-radius: 8px;"></div>
            <div style="flex: 1;">
              <div class="skeleton-loader skeleton-line"></div>
              <div class="skeleton-loader skeleton-line short"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    // Animation control functionality
    function toggleAnimation(element) {
      const style = window.getComputedStyle(element);
      const animationState = style.animationPlayState;
      
      if (animationState === 'paused') {
        element.style.animationPlayState = 'running';
      } else {
        element.style.animationPlayState = 'paused';
      }
    }
    
    // Simulate loading states
    function simulateLoading(duration = 2000) {
      const loaders = document.querySelectorAll('.spinner, .dots-loader, .progress-loader, .pulse-loader');
      
      loaders.forEach(loader => {
        loader.style.animationPlayState = 'running';
      });
      
      // Show loading message
      console.log('Simulating loading for ' + duration + 'ms');
      
      setTimeout(() => {
        console.log('Loading complete!');
      }, duration);
    }
    
    // Initialize with a loading simulation
    setTimeout(() => {
      simulateLoading(3000);
    }, 1000);
    
    // Add click handlers to demo buttons
    const demoButtons = document.querySelectorAll('.demo-btn');
    demoButtons.forEach(button => {
      if (button.textContent === 'Pause/Resume') {
        button.addEventListener('click', function() {
          const loader = this.previousElementSibling;
          toggleAnimation(loader);
        });
      }
    });
  </script>
</body>
</html>

Advanced CSS Loading Animations

Creative Animations

Create engaging loading animations with wave effects, morphing shapes, 3D transformations, and gradient spinners that capture user attention.

Wave and morph animations
3D cube loaders
Gradient effects

Interactive Features

Implement interactive loading animations with speed controls, color customization, and real-time adjustments for enhanced user control.

Speed adjustment
Color customization
Interactive controls

Advanced Loading Animations Demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Advanced CSS Loading Animations</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Inter', sans-serif;
      line-height: 1.6;
      background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
      min-height: 100vh;
      padding: 2rem;
    }
    
    .container {
      max-width: 1200px;
      margin: 0 auto;
      background: white;
      border-radius: 20px;
      padding: 3rem;
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    }
    
    h1 {
      color: #2d3748;
      margin-bottom: 2rem;
      text-align: center;
      font-size: 2.5rem;
    }
    
    .loading-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 2rem;
      margin: 2rem 0;
    }
    
    .loading-group {
      padding: 2rem;
      background: #f8fafc;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
    }
    
    .loading-title {
      font-weight: 600;
      color: #2d3748;
      margin-bottom: 1.5rem;
      font-size: 1.2rem;
    }
    
    /* Wave Loader */
    .wave-loader {
      display: flex;
      justify-content: center;
      gap: 5px;
      height: 50px;
      align-items: flex-end;
    }
    
    .wave-bar {
      width: 8px;
      background: #3b82f6;
      border-radius: 4px;
      animation: wave 1.2s infinite ease-in-out;
    }
    
    .wave-bar:nth-child(1) { animation-delay: 0s; height: 20px; }
    .wave-bar:nth-child(2) { animation-delay: 0.1s; height: 30px; }
    .wave-bar:nth-child(3) { animation-delay: 0.2s; height: 40px; }
    .wave-bar:nth-child(4) { animation-delay: 0.3s; height: 50px; }
    .wave-bar:nth-child(5) { animation-delay: 0.4s; height: 40px; }
    .wave-bar:nth-child(6) { animation-delay: 0.5s; height: 30px; }
    .wave-bar:nth-child(7) { animation-delay: 0.6s; height: 20px; }
    
    @keyframes wave {
      0%, 40%, 100% {
        transform: scaleY(0.8);
      }
      20% {
        transform: scaleY(1.2);
      }
    }
    
    /* Morphing Loader */
    .morphing-loader {
      width: 50px;
      height: 50px;
      background: #3b82f6;
      border-radius: 50%;
      margin: 0 auto;
      animation: morph 2s infinite ease-in-out;
    }
    
    @keyframes morph {
      0%, 100% {
        border-radius: 50%;
        transform: scale(1) rotate(0deg);
      }
      25% {
        border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
        transform: scale(1.1) rotate(90deg);
      }
      50% {
        border-radius: 70% 30% 30% 70% / 70% 70% 30% 30%;
        transform: scale(1.2) rotate(180deg);
      }
      75% {
        border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
        transform: scale(1.1) rotate(270deg);
      }
    }
    
    /* Infinity Loader */
    .infinity-loader {
      width: 60px;
      height: 30px;
      position: relative;
      margin: 0 auto;
    }
    
    .infinity-loader:before,
    .infinity-loader:after {
      content: "";
      position: absolute;
      top: 0;
      width: 30px;
      height: 30px;
      border: 4px solid #3b82f6;
      border-radius: 50px 50px 0 50px;
      transform: rotate(45deg);
      animation: infinity 1.5s infinite;
    }
    
    .infinity-loader:after {
      left: 30px;
      border-radius: 50px 50px 50px 0;
      transform: rotate(-135deg);
      animation-delay: 0.75s;
    }
    
    @keyframes infinity {
      0%, 100% {
        opacity: 0.3;
      }
      50% {
        opacity: 1;
      }
    }
    
    /* Gradient Spinner */
    .gradient-spinner {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      background: conic-gradient(#3b82f6, #10b981, #f59e0b, #ef4444, #3b82f6);
      mask: radial-gradient(circle, transparent 40%, black 41%);
      -webkit-mask: radial-gradient(circle, transparent 40%, black 41%);
      animation: rotate 1.5s linear infinite;
      margin: 0 auto;
    }
    
    @keyframes rotate {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    
    /* Text Loading Animation */
    .text-loader {
      text-align: center;
      font-size: 1.5rem;
      font-weight: 600;
      color: #3b82f6;
    }
    
    .text-loader span {
      display: inline-block;
      animation: textBounce 1.5s infinite ease-in-out;
    }
    
    .text-loader span:nth-child(1) { animation-delay: 0s; }
    .text-loader span:nth-child(2) { animation-delay: 0.1s; }
    .text-loader span:nth-child(3) { animation-delay: 0.2s; }
    .text-loader span:nth-child(4) { animation-delay: 0.3s; }
    .text-loader span:nth-child(5) { animation-delay: 0.4s; }
    .text-loader span:nth-child(6) { animation-delay: 0.5s; }
    .text-loader span:nth-child(7) { animation-delay: 0.6s; }
    
    @keyframes textBounce {
      0%, 40%, 100% {
        transform: translateY(0);
      }
      20% {
        transform: translateY(-10px);
      }
    }
    
    /* 3D Cube Loader */
    .cube-loader {
      width: 40px;
      height: 40px;
      position: relative;
      transform-style: preserve-3d;
      animation: cubeRotate 3s infinite linear;
      margin: 0 auto;
    }
    
    .cube-face {
      position: absolute;
      width: 100%;
      height: 100%;
      background: rgba(59, 130, 246, 0.8);
      border: 1px solid #1e40af;
    }
    
    .cube-face:nth-child(1) { transform: rotateY(0deg) translateZ(20px); }
    .cube-face:nth-child(2) { transform: rotateY(90deg) translateZ(20px); }
    .cube-face:nth-child(3) { transform: rotateY(180deg) translateZ(20px); }
    .cube-face:nth-child(4) { transform: rotateY(270deg) translateZ(20px); }
    .cube-face:nth-child(5) { transform: rotateX(90deg) translateZ(20px); }
    .cube-face:nth-child(6) { transform: rotateX(-90deg) translateZ(20px); }
    
    @keyframes cubeRotate {
      0% { transform: rotateX(0) rotateY(0) rotateZ(0); }
      100% { transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg); }
    }
    
    /* Neon Glow Loader */
    .neon-loader {
      width: 50px;
      height: 50px;
      border: 3px solid #3b82f6;
      border-radius: 50%;
      margin: 0 auto;
      position: relative;
      animation: neonPulse 2s infinite ease-in-out;
    }
    
    .neon-loader:before {
      content: "";
      position: absolute;
      top: -3px;
      left: -3px;
      right: -3px;
      bottom: -3px;
      border: 3px solid transparent;
      border-top: 3px solid #3b82f6;
      border-radius: 50%;
      animation: neonSpin 1.5s infinite linear;
    }
    
    @keyframes neonPulse {
      0%, 100% {
        box-shadow: 0 0 5px #3b82f6, 0 0 10px #3b82f6;
      }
      50% {
        box-shadow: 0 0 20px #3b82f6, 0 0 30px #3b82f6;
      }
    }
    
    @keyframes neonSpin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    
    /* Demo Controls */
    .demo-controls {
      display: flex;
      gap: 1rem;
      margin: 1rem 0;
      flex-wrap: wrap;
    }
    
    .demo-btn {
      padding: 8px 16px;
      background: #3b82f6;
      color: white;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 0.875rem;
      transition: background 0.2s ease;
    }
    
    .demo-btn:hover {
      background: #2563eb;
    }
    
    /* Demo Section */
    .demo-section {
      background: #f8fafc;
      padding: 2rem;
      border-radius: 15px;
      margin: 2rem 0;
      border-left: 4px solid #4facfe;
    }
    
    .code-example {
      background: #2d3748;
      color: #81e6d9;
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      margin: 1rem 0;
      font-size: 0.9rem;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>🚀 Advanced CSS Loading Animations</h1>
    
    <div class="demo-section">
      <h2>Creative Loading Animations</h2>
      <div class="code-example">
        /* Advanced CSS Animations */<br>
        Complex keyframe animations<br>
        3D transforms and effects<br>
        Creative visual patterns
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">Wave Loader</div>
          <div class="wave-loader">
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
            <div class="wave-bar"></div>
          </div>
          <div class="demo-controls">
            <button class="demo-btn" onclick="toggleAnimation(this.previousElementSibling)">Pause/Resume</button>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Morphing Loader</div>
          <div class="morphing-loader"></div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Infinity Loader</div>
          <div class="infinity-loader"></div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Gradient Spinner</div>
          <div class="gradient-spinner"></div>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Special Effects Loaders</h2>
      <div class="code-example">
        /* Special Effects */<br>
        3D transformations<br>
        Neon glow effects<br>
        Text animations
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">3D Cube Loader</div>
          <div class="cube-loader">
            <div class="cube-face"></div>
            <div class="cube-face"></div>
            <div class="cube-face"></div>
            <div class="cube-face"></div>
            <div class="cube-face"></div>
            <div class="cube-face"></div>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Neon Glow Loader</div>
          <div class="neon-loader"></div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Text Animation</div>
          <div class="text-loader">
            <span>L</span>
            <span>O</span>
            <span>A</span>
            <span>D</span>
            <span>I</span>
            <span>N</span>
            <span>G</span>
          </div>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Interactive Loaders</h2>
      <div class="code-example">
        /* Interactive Features */<br>
        Animation controls<br>
        Speed adjustments<br>
        Real-time customization
      </div>
      
      <div class="loading-grid">
        <div class="loading-group">
          <div class="loading-title">Speed Control</div>
          <div class="spinner" id="speedSpinner"></div>
          <div class="demo-controls">
            <button class="demo-btn" onclick="changeSpeed(0.5)">Slow</button>
            <button class="demo-btn" onclick="changeSpeed(1)">Normal</button>
            <button class="demo-btn" onclick="changeSpeed(2)">Fast</button>
          </div>
        </div>
        
        <div class="loading-group">
          <div class="loading-title">Color Picker</div>
          <div class="spinner" id="colorSpinner"></div>
          <div class="demo-controls">
            <button class="demo-btn" onclick="changeColor('#3b82f6')">Blue</button>
            <button class="demo-btn" onclick="changeColor('#10b981')">Green</button>
            <button class="demo-btn" onclick="changeColor('#f59e0b')">Orange</button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    // Animation control functionality
    function toggleAnimation(element) {
      const style = window.getComputedStyle(element);
      const animationState = style.animationPlayState;
      
      if (animationState === 'paused') {
        element.style.animationPlayState = 'running';
      } else {
        element.style.animationPlayState = 'paused';
      }
    }
    
    // Speed control functionality
    function changeSpeed(speed) {
      const spinner = document.getElementById('speedSpinner');
      spinner.style.animationDuration = (1 / speed) + 's';
      console.log('Animation speed changed to: ' + speed + 'x');
    }
    
    // Color control functionality
    function changeColor(color) {
      const spinner = document.getElementById('colorSpinner');
      spinner.style.borderTopColor = color;
      console.log('Spinner color changed to: ' + color);
    }
    
    // Initialize with some interactive features
    document.addEventListener('DOMContentLoaded', function() {
      // Add hover effects to loaders
      const loaders = document.querySelectorAll('.spinner, .morphing-loader, .gradient-spinner');
      
      loaders.forEach(loader => {
        loader.addEventListener('mouseenter', function() {
          this.style.transform = 'scale(1.1)';
        });
        
        loader.addEventListener('mouseleave', function() {
          this.style.transform = 'scale(1)';
        });
      });
      
      // Log animation events
      const advancedLoaders = document.querySelectorAll('.wave-loader, .infinity-loader, .cube-loader');
      
      advancedLoaders.forEach(loader => {
        loader.addEventListener('animationiteration', function() {
          console.log('Animation iteration completed for: ' + this.className);
        });
      });
    });
    
    // Simulate complex loading
    function simulateComplexLoading() {
      console.log('Starting complex loading simulation...');
      
      const stages = ['Initializing...', 'Processing data...', 'Rendering components...', 'Finalizing...'];
      let stage = 0;
      
      const interval = setInterval(() => {
        if (stage < stages.length) {
          console.log(stages[stage]);
          stage++;
        } else {
          clearInterval(interval);
          console.log('Complex loading complete!');
        }
      }, 1000);
    }
    
    // Start simulation after page load
    setTimeout(simulateComplexLoading, 2000);
  </script>
</body>
</html>

Page Loading Animations

Full Page Loading Patterns

Implement comprehensive page loading solutions including full-screen loaders, progress bars, content fade-ins, and staggered animations for optimal user experience.

Full-screen loaders
Progress indicators
Staggered content loading

Page Loading Animations Demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Loading Animations</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Inter', sans-serif;
      line-height: 1.6;
      background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
      min-height: 100vh;
      padding: 1rem;
    }
    
    .container {
      max-width: 800px;
      margin: 0 auto;
      background: white;
      border-radius: 20px;
      padding: 2rem;
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    }
    
    h1 {
      color: #2d3748;
      margin-bottom: 1.5rem;
      text-align: center;
      font-size: 1.8rem;
    }
    
    .loading-group {
      margin-bottom: 2rem;
      padding: 1.5rem;
      background: #f8fafc;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
    }
    
    .loading-title {
      font-weight: 600;
      color: #2d3748;
      margin-bottom: 1rem;
      font-size: 1.1rem;
    }
    
    /* Full Page Loader */
    .fullpage-loader {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: white;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      z-index: 9999;
      transition: opacity 0.5s ease, visibility 0.5s ease;
    }
    
    .fullpage-loader.hidden {
      opacity: 0;
      visibility: hidden;
    }
    
    .fullpage-spinner {
      width: 60px;
      height: 60px;
      border: 4px solid #e2e8f0;
      border-top: 4px solid #3b82f6;
      border-radius: 50%;
      animation: spin 1s linear infinite;
      margin-bottom: 1rem;
    }
    
    .loading-text {
      font-size: 1.125rem;
      color: #6b7280;
      text-align: center;
    }
    
    /* Progress Loader */
    .progress-loader {
      width: 100%;
      height: 4px;
      background: #e2e8f0;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10000;
    }
    
    .progress-bar {
      height: 100%;
      background: #3b82f6;
      width: 0%;
      transition: width 0.3s ease;
    }
    
    /* Content Fade In */
    .content {
      opacity: 0;
      transform: translateY(20px);
      transition: all 0.6s ease;
    }
    
    .content.loaded {
      opacity: 1;
      transform: translateY(0);
    }
    
    /* Staggered Loading */
    .stagger-item {
      opacity: 0;
      transform: translateY(20px);
      transition: all 0.5s ease;
    }
    
    .stagger-item.loaded {
      opacity: 1;
      transform: translateY(0);
    }
    
    /* Demo Content */
    .demo-card {
      background: white;
      border-radius: 12px;
      padding: 1.5rem;
      margin: 1rem 0;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      border: 1px solid #e5e7eb;
    }
    
    .demo-header {
      display: flex;
      align-items: center;
      gap: 1rem;
      margin-bottom: 1rem;
    }
    
    .demo-avatar {
      width: 50px;
      height: 50px;
      background: #3b82f6;
      border-radius: 50%;
    }
    
    .demo-content {
      height: 20px;
      background: #f3f4f6;
      border-radius: 4px;
      margin-bottom: 0.5rem;
    }
    
    .demo-content.short {
      width: 60%;
    }
    
    /* Button Styles */
    .demo-btn {
      padding: 12px 24px;
      background: #3b82f6;
      color: white;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 1rem;
      transition: background 0.2s ease;
      margin: 0.5rem;
    }
    
    .demo-btn:hover {
      background: #2563eb;
    }
    
    .demo-btn:disabled {
      background: #9ca3af;
      cursor: not-allowed;
    }
    
    /* Demo Section */
    .demo-section {
      background: #f8fafc;
      padding: 1.5rem;
      border-radius: 12px;
      margin: 1.5rem 0;
      border-left: 4px solid #ff9a9e;
    }
    
    .code-example {
      background: #2d3748;
      color: #81e6d9;
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      margin: 1rem 0;
      font-size: 0.8rem;
    }
  </style>
</head>
<body>
  <!-- Full Page Loader -->
  <div class="fullpage-loader" id="fullpageLoader">
    <div class="fullpage-spinner"></div>
    <div class="loading-text">Loading amazing content...</div>
  </div>

  <!-- Progress Loader -->
  <div class="progress-loader" id="progressLoader">
    <div class="progress-bar" id="progressBar"></div>
  </div>

  <div class="container">
    <h1>📄 Page Loading Animations</h1>
    
    <div class="demo-section">
      <h2>Full Page Loading</h2>
      <div class="code-example">
        /* Full Page Loader */<br>
        Cover entire viewport<br>
        Center loading indicator<br>
        Smooth fade-out transition
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Page Load Simulation</div>
        <p style="margin-bottom: 1rem; color: #6b7280;">
          Click the button below to simulate a page load with loading animation.
        </p>
        <button class="demo-btn" onclick="simulatePageLoad()">Simulate Page Load</button>
        <button class="demo-btn" onclick="showFullPageLoader()">Show Loader</button>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Content Loading Effects</h2>
      <div class="code-example">
        /* Content Animations */<br>
        Fade-in effects<br>
        Staggered animations<br>
        Smooth transitions
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Staggered Content Load</div>
        <div id="staggerContent">
          <div class="stagger-item demo-card">
            <div class="demo-header">
              <div class="demo-avatar"></div>
              <div style="flex: 1;">
                <div class="demo-content"></div>
                <div class="demo-content short"></div>
              </div>
            </div>
            <div class="demo-content"></div>
            <div class="demo-content"></div>
            <div class="demo-content short"></div>
          </div>
          
          <div class="stagger-item demo-card">
            <div class="demo-header">
              <div class="demo-avatar"></div>
              <div style="flex: 1;">
                <div class="demo-content"></div>
                <div class="demo-content short"></div>
              </div>
            </div>
            <div class="demo-content"></div>
            <div class="demo-content"></div>
            <div class="demo-content short"></div>
          </div>
        </div>
        <button class="demo-btn" onclick="loadStaggerContent()">Load Content</button>
        <button class="demo-btn" onclick="resetStaggerContent()">Reset</button>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Progress Indicators</h2>
      <div class="code-example">
        /* Progress Loading */<br>
        Top progress bar<br>
        Simulated progress<br>
        Real-time updates
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Simulated Progress</div>
        <p style="margin-bottom: 1rem; color: #6b7280;">
          Simulate different loading scenarios with progress indication.
        </p>
        <button class="demo-btn" onclick="startProgress()">Start Progress</button>
        <button class="demo-btn" onclick="simulateSlowLoad()">Slow Load</button>
        <button class="demo-btn" onclick="simulateFastLoad()">Fast Load</button>
      </div>
    </div>
    
    <div class="content" id="mainContent">
      <div class="demo-section">
        <h2>Loaded Content Area</h2>
        <div class="loading-group">
          <div class="loading-title">Dynamic Content</div>
          <p style="margin-bottom: 1rem; color: #6b7280;">
            This content area demonstrates how loaded content can appear with smooth animations.
          </p>
          <div class="demo-card">
            <h3 style="margin-bottom: 1rem; color: #1f2937;">Welcome to the loaded content!</h3>
            <p style="color: #6b7280; line-height: 1.6;">
              This content appears with a smooth fade-in animation after the loading process completes. 
              You can see how proper loading animations enhance the user experience by providing 
              visual feedback during content loading.
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    // Page load simulation
    function simulatePageLoad() {
      const loader = document.getElementById('fullpageLoader');
      const content = document.getElementById('mainContent');
      const progressBar = document.getElementById('progressBar');
      
      // Show loader and hide content
      loader.classList.remove('hidden');
      content.classList.remove('loaded');
      
      // Reset progress
      progressBar.style.width = '0%';
      
      // Simulate loading progress
      let progress = 0;
      const interval = setInterval(() => {
        progress += Math.random() * 15;
        if (progress >= 100) {
          progress = 100;
          clearInterval(interval);
          
          // Complete loading
          setTimeout(() => {
            loader.classList.add('hidden');
            content.classList.add('loaded');
          }, 500);
        }
        progressBar.style.width = progress + '%';
      }, 200);
    }
    
    // Show full page loader
    function showFullPageLoader() {
      const loader = document.getElementById('fullpageLoader');
      loader.classList.remove('hidden');
      
      setTimeout(() => {
        loader.classList.add('hidden');
      }, 3000);
    }
    
    // Staggered content loading
    function loadStaggerContent() {
      const items = document.querySelectorAll('.stagger-item');
      
      items.forEach((item, index) => {
        setTimeout(() => {
          item.classList.add('loaded');
        }, index * 200);
      });
    }
    
    // Reset staggered content
    function resetStaggerContent() {
      const items = document.querySelectorAll('.stagger-item');
      items.forEach(item => {
        item.classList.remove('loaded');
      });
    }
    
    // Progress simulation
    function startProgress() {
      const progressBar = document.getElementById('progressBar');
      progressBar.style.width = '0%';
      
      let width = 0;
      const interval = setInterval(() => {
        if (width >= 100) {
          clearInterval(interval);
        } else {
          width++;
          progressBar.style.width = width + '%';
        }
      }, 30);
    }
    
    function simulateSlowLoad() {
      const progressBar = document.getElementById('progressBar');
      progressBar.style.width = '0%';
      
      let width = 0;
      const interval = setInterval(() => {
        if (width >= 100) {
          clearInterval(interval);
        } else {
          width += 0.5;
          progressBar.style.width = width + '%';
        }
      }, 50);
    }
    
    function simulateFastLoad() {
      const progressBar = document.getElementById('progressBar');
      progressBar.style.width = '0%';
      
      let width = 0;
      const interval = setInterval(() => {
        if (width >= 100) {
          clearInterval(interval);
        } else {
          width += 5;
          progressBar.style.width = width + '%';
        }
      }, 50);
    }
    
    // Initialize page
    document.addEventListener('DOMContentLoaded', function() {
      // Hide full page loader after initial load
      setTimeout(() => {
        document.getElementById('fullpageLoader').classList.add('hidden');
        document.getElementById('mainContent').classList.add('loaded');
      }, 2000);
      
      // Initialize progress bar
      document.getElementById('progressBar').style.width = '100%';
      setTimeout(() => {
        document.getElementById('progressLoader').style.opacity = '0';
      }, 500);
    });
    
    // Log loading events
    window.addEventListener('load', function() {
      console.log('Page fully loaded');
    });
    
    document.addEventListener('DOMContentLoaded', function() {
      console.log('DOM content loaded');
    });
  </script>
</body>
</html>

Accessibility & Best Practices

🎯 Reduced Motion

Respect user motion preferences

🌈 ARIA Attributes

Proper loading states and announcements

📝 Focus Management

Maintain and restore focus during loading

Accessibility Demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Accessible CSS Loading Animations</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Inter', sans-serif;
      line-height: 1.6;
      background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
      min-height: 100vh;
      padding: 2rem;
    }
    
    .container {
      max-width: 800px;
      margin: 0 auto;
      background: white;
      border-radius: 20px;
      padding: 3rem;
      box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
    }
    
    h1 {
      color: #2d3748;
      margin-bottom: 2rem;
      text-align: center;
      font-size: 2.5rem;
    }
    
    .loading-group {
      margin-bottom: 2rem;
      padding: 1.5rem;
      background: #f8fafc;
      border-radius: 12px;
      border: 1px solid #e2e8f0;
    }
    
    .loading-title {
      font-weight: 600;
      color: #2d3748;
      margin-bottom: 1rem;
      font-size: 1.1rem;
    }
    
    .accessibility-note {
      background: #e6fffa;
      border: 1px solid #81e6d9;
      border-radius: 8px;
      padding: 1rem;
      margin: 1rem 0;
      font-size: 0.9rem;
    }
    
    .accessibility-note.error {
      background: #fed7d7;
      border-color: #feb2b2;
    }
    
    /* Accessible Spinner */
    .acc-spinner {
      width: 50px;
      height: 50px;
      border: 4px solid #e2e8f0;
      border-top: 4px solid #1e40af;
      border-radius: 50%;
      animation: spin 1s linear infinite;
      margin: 0 auto;
    }
    
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    
    /* High Contrast Support */
    @media (prefers-contrast: high) {
      .acc-spinner {
        border-width: 5px;
        border-top-color: #0000ff;
      }
    }
    
    /* Reduced Motion Support */
    @media (prefers-reduced-motion: reduce) {
      .acc-spinner {
        animation: none;
        border-top-color: #1e40af;
      }
      
      .pulse-loader {
        animation: none;
        opacity: 0.7;
      }
    }
    
    /* Accessible Progress Bar */
    .acc-progress {
      width: 100%;
      height: 8px;
      background: #e2e8f0;
      border-radius: 4px;
      overflow: hidden;
      position: relative;
    }
    
    .acc-progress-bar {
      height: 100%;
      background: #1e40af;
      border-radius: 4px;
      width: 0%;
      transition: width 0.3s ease;
    }
    
    /* Screen Reader Only */
    .sr-only {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }
    
    /* Loading States with ARIA */
    .loading-region {
      position: relative;
    }
    
    .loading-region[aria-busy="true"] {
      opacity: 0.7;
      pointer-events: none;
    }
    
    .loading-message {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: rgba(0, 0, 0, 0.8);
      color: white;
      padding: 1rem;
      border-radius: 8px;
      z-index: 1000;
    }
    
    /* Demo Content */
    .demo-content {
      background: white;
      border: 2px solid #e5e7eb;
      border-radius: 8px;
      padding: 1.5rem;
      margin: 1rem 0;
    }
    
    /* Button Styles */
    .demo-btn {
      padding: 12px 24px;
      background: #1e40af;
      color: white;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 1rem;
      transition: background 0.2s ease;
      margin: 0.5rem;
    }
    
    .demo-btn:hover {
      background: #1e3a8a;
    }
    
    .demo-btn:focus {
      outline: 3px solid #3b82f6;
      outline-offset: 2px;
    }
    
    .demo-btn:disabled {
      background: #9ca3af;
      cursor: not-allowed;
    }
    
    /* Demo Section */
    .demo-section {
      background: #f8fafc;
      padding: 2rem;
      border-radius: 15px;
      margin: 2rem 0;
      border-left: 4px solid #a8edea;
    }
    
    .code-example {
      background: #2d3748;
      color: #81e6d9;
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      margin: 1rem 0;
      font-size: 0.9rem;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>♿ Accessible Loading Animations</h1>
    
    <div class="demo-section">
      <h2>Reduced Motion Support</h2>
      <div class="code-example">
        /* Reduced Motion Media Query */<br>
        @media (prefers-reduced-motion: reduce) {<br>
        &nbsp;&nbsp;.spinner {<br>
        &nbsp;&nbsp;&nbsp;&nbsp;animation: none;<br>
        &nbsp;&nbsp;&nbsp;&nbsp;border-top-color: #1e40af;<br>
        &nbsp;&nbsp;}<br>
        }
      </div>
      
      <div class="accessibility-note">
        ✅ <strong>Good:</strong> Respect users' motion preferences by providing alternative static indicators.
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Reduced Motion Demo</div>
        <div class="acc-spinner"></div>
        <p style="text-align: center; margin-top: 1rem; color: #6b7280;">
          This spinner respects the <code>prefers-reduced-motion</code> setting.
        </p>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>ARIA Loading States</h2>
      <div class="code-example">
        /* ARIA Loading Attributes */<br>
        aria-busy="true" for loading state<br>
        aria-live for dynamic updates<br>
        aria-describedby for status messages
      </div>
      
      <div class="loading-group">
        <div class="loading-title">ARIA Loading Region</div>
        <div class="loading-region" id="loadingRegion" aria-busy="false">
          <div class="demo-content">
            <h3>Interactive Content Area</h3>
            <p>This content area demonstrates ARIA loading states.</p>
            <button class="demo-btn" onclick="toggleLoadingRegion()">Toggle Loading State</button>
          </div>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Screen Reader Announcements</h2>
      <div class="code-example">
        /* Screen Reader Support */<br>
        Use aria-live regions<br>
        Provide status updates<br>
        Clear completion messages
      </div>
      
      <div class="accessibility-note">
        ✅ <strong>Good:</strong> Screen readers should announce loading states and completion.
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Loading with Announcements</div>
        <div aria-live="polite" aria-atomic="true" class="sr-only" id="loadingStatus">
          Content is ready.
        </div>
        
        <div class="acc-progress" style="margin-bottom: 1rem;">
          <div class="acc-progress-bar" id="accessibleProgress"></div>
        </div>
        
        <div style="display: flex; gap: 1rem; flex-wrap: wrap;">
          <button class="demo-btn" onclick="startAccessibleProgress()">Start Loading</button>
          <button class="demo-btn" onclick="announceLoading('Loading complete!')">Announce Complete</button>
          <button class="demo-btn" onclick="resetProgress()">Reset</button>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Focus Management</h2>
      <div class="code-example">
        /* Focus Management */<br>
        Maintain focus during loading<br>
        Return focus after completion<br>
        Prevent focus loss
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Focus Demo</div>
        <div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;">
          <button class="demo-btn" id="focusButton" onclick="simulateLoadingWithFocus()">Load Data</button>
          <button class="demo-btn">Other Button</button>
          <button class="demo-btn">Another Button</button>
        </div>
        
        <div id="focusContent" style="min-height: 100px; padding: 1rem; background: #f8fafc; border-radius: 8px;">
          <p>Content will appear here after loading...</p>
        </div>
      </div>
    </div>
    
    <div class="demo-section">
      <h2>Alternative Loading Indicators</h2>
      <div class="code-example">
        /* Alternative Indicators */<br>
        Text-based loading<br>
        Static progress indicators<br>
        Non-animated alternatives
      </div>
      
      <div class="accessibility-note">
        ✅ <strong>Good:</strong> Provide multiple ways to indicate loading for different user needs.
      </div>
      
      <div class="loading-group">
        <div class="loading-title">Text-based Loading</div>
        <div id="textLoading" style="text-align: center; padding: 2rem;">
          <p style="font-size: 1.125rem; color: #1e40af; margin-bottom: 1rem;">Loading content...</p>
          <div class="acc-progress">
            <div class="acc-progress-bar" style="width: 70%;"></div>
          </div>
          <p style="margin-top: 1rem; color: #6b7280;">70% complete</p>
        </div>
      </div>
    </div>
  </div>

  <script>
    // Accessible loading functionality
    function toggleLoadingRegion() {
      const region = document.getElementById('loadingRegion');
      const isBusy = region.getAttribute('aria-busy') === 'true';
      
      if (isBusy) {
        region.setAttribute('aria-busy', 'false');
        region.querySelector('.demo-content').innerHTML = `
          <h3>Interactive Content Area</h3>
          <p>This content area demonstrates ARIA loading states.</p>
          <button class="demo-btn" onclick="toggleLoadingRegion()">Toggle Loading State</button>
        `;
      } else {
        region.setAttribute('aria-busy', 'true');
        region.querySelector('.demo-content').innerHTML = `
          <div class="acc-spinner" style="margin: 0 auto 1rem auto;"></div>
          <p style="text-align: center;">Loading content...</p>
        `;
      }
    }
    
    // Accessible progress functionality
    function startAccessibleProgress() {
      const progressBar = document.getElementById('accessibleProgress');
      const status = document.getElementById('loadingStatus');
      
      progressBar.style.width = '0%';
      status.textContent = 'Loading started.';
      
      let width = 0;
      const interval = setInterval(() => {
        if (width >= 100) {
          clearInterval(interval);
          status.textContent = 'Loading complete!';
        } else {
          width += 2;
          progressBar.style.width = width + '%';
          
          // Update status at key points
          if (width === 25) status.textContent = 'Loading 25% complete.';
          if (width === 50) status.textContent = 'Loading 50% complete.';
          if (width === 75) status.textContent = 'Loading 75% complete.';
        }
      }, 50);
    }
    
    function resetProgress() {
      const progressBar = document.getElementById('accessibleProgress');
      const status = document.getElementById('loadingStatus');
      
      progressBar.style.width = '0%';
      status.textContent = 'Progress reset.';
    }
    
    function announceLoading(message) {
      const status = document.getElementById('loadingStatus');
      status.textContent = message;
    }
    
    // Focus management demo
    function simulateLoadingWithFocus() {
      const button = document.getElementById('focusButton');
      const content = document.getElementById('focusContent');
      
      // Store current focus
      const focusedElement = document.activeElement;
      
      // Show loading state
      content.innerHTML = `
        <div class="acc-spinner" style="margin: 0 auto;"></div>
        <p style="text-align: center; margin-top: 1rem;">Loading data, please wait...</p>
      `;
      
      // Disable button during loading
      button.disabled = true;
      button.textContent = 'Loading...';
      
      // Simulate async operation
      setTimeout(() => {
        // Restore content
        content.innerHTML = `
          <h3>Data Loaded Successfully!</h3>
          <p>Your data has been loaded and is now ready to use.</p>
          <ul>
            <li>Data point 1: 42 results</li>
            <li>Data point 2: 156 items</li>
            <li>Data point 3: 7 categories</li>
          </ul>
        `;
        
        // Re-enable button
        button.disabled = false;
        button.textContent = 'Load Data';
        
        // Return focus or move to new content
        content.focus();
        content.setAttribute('tabindex', '-1');
      }, 3000);
    }
    
    // Initialize accessibility features
    document.addEventListener('DOMContentLoaded', function() {
      // Check for reduced motion preference
      const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (reducedMotion) {
        console.log('Reduced motion preference detected - using simplified animations');
      }
      
      // Add keyboard event listeners
      document.addEventListener('keydown', function(event) {
        if (event.key === 'Escape') {
          // Allow users to cancel loading with Escape
          const loadingElements = document.querySelectorAll('[aria-busy="true"]');
          loadingElements.forEach(element => {
            element.setAttribute('aria-busy', 'false');
          });
        }
      });
    });
    
    // Screen reader announcement function
    function announceToScreenReader(message) {
      const announcement = document.createElement('div');
      announcement.setAttribute('aria-live', 'polite');
      announcement.setAttribute('aria-atomic', 'true');
      announcement.classList.add('sr-only');
      announcement.textContent = message;
      
      document.body.appendChild(announcement);
      
      setTimeout(() => {
        document.body.removeChild(announcement);
      }, 1000);
    }
  </script>
</body>
</html>

Best Practices & Performance

✅ Do This

  • Use CSS animations for better performance
  • Provide accessible loading states
  • Respect reduced motion preferences
  • Use appropriate animation durations
  • Test with screen readers
  • Provide loading status announcements

❌ Avoid This

  • Don't use excessive or distracting animations
  • Avoid long loading times without progress indication
  • Don't ignore motion sensitivity
  • Avoid blocking user interaction unnecessarily
  • Don't forget to handle loading errors
  • Avoid complex animations on low-powered devices

🚀 Performance Tips

CSS Animations

Use transform and opacity for better performance

GPU Acceleration

Leverage GPU with transform3d for smooth animations

Reduced Motion

Respect prefers-reduced-motion preference

Efficient Keyframes

Use simple keyframe animations for better performance

Ready to Create Amazing Loading Animations? ⏳

Experiment with our comprehensive loading animation examples and create beautiful, accessible user interfaces that provide excellent feedback during loading states.

< PreviousNext >