Back

Creating an Elegant Ripple Dot Loading Animation

Learn how to build a smooth, accessible loading indicator with rippling dots using pure CSS animations.

HTML

The HTML structure for our ripple dot loader is beautifully simple. We need a container with the class "ripple-loader" that houses five div elements with the class "dot". Each dot will animate independently to create our ripple effect.
        <div class="ripple-loader">
          <div class="dot"></div>
          <div class="dot"></div>
          <div class="dot"></div>
          <div class="dot"></div>
          <div class="dot"></div>
        </div>
      

CSS

Let's start by setting up our loader container. We'll use flexbox to create a horizontal row of dots with consistent spacing. The gap property creates an equal 8px space between each dot, while the height provides adequate room for the animation. By centering both horizontally and vertically, we ensure our loader appears balanced regardless of its container.
        .ripple-loader {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            height: 60px;
        }
      
Next, let's style each dot. We'll create small 12×12px circles using border-radius: 50% and give them a vibrant indigo color (#6366F1) that provides good contrast without being too harsh. Initially, we set them to scale(0) so they're invisible at the start of the animation. The animation property applies our "ripple" animation to run for 1.5 seconds, repeat infinitely, and use linear timing for consistent speed throughout the sequence.
        .dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background-color: #6366F1;
            transform: scale(0);
            animation: ripple 1.5s linear infinite;
        }
      
To create the ripple effect, we'll stagger the animation start time for each dot. Using the nth-child selector, we add incremental delays of 0.2 seconds to each dot after the first. This creates a wave-like motion as each dot follows the previous one in the animation sequence, giving the impression of energy flowing across the loader.
        .dot:nth-child(2) {
            animation-delay: 0.2s;
        }

        .dot:nth-child(3) {
            animation-delay: 0.4s;
        }

        .dot:nth-child(4) {
            animation-delay: 0.6s;
        }

        .dot:nth-child(5) {
            animation-delay: 0.8s;
        }
      
The heart of our animation is the @keyframes rule. This sequence creates a smooth cycle where each dot grows from nothing, reaches full size, and then shrinks away again. At 0%, the dot is invisible (scale(0)) with partial opacity. By 40% of the animation time, it reaches full size (scale(1)) and full opacity, creating a satisfying "pop" effect. At 80%, it shrinks back to nothing, maintaining this state until the cycle repeats. The opacity changes enhance the visual effect, making the animation feel more natural and fluid.
        @keyframes ripple {
            0% {
                transform: scale(0);
                opacity: 0.8;
            }
            40% {
                transform: scale(1);
                opacity: 1;
            }
            80% {
                transform: scale(0);
                opacity: 0.8;
            }
            100% {
                transform: scale(0);
                opacity: 0.8;
            }
        }
      
This loader design offers several advantages for modern web applications: - Accessibility: The animation is subtle enough not to distract users but provides clear feedback that processing is happening. - Performance: By using CSS transform properties instead of dimensions for animation, we leverage hardware acceleration for smoother performance even on lower-powered devices. - Responsiveness: The loader maintains its appearance across screen sizes and adapts well to both light and dark themes with appropriate color adjustments. - User experience: The ripple pattern creates an intuitive sense of progress and activity, reducing perceived wait times compared to static loaders. The clean, cohesive animation provides users with a polished experience while waiting for content to load, helping maintain engagement during necessary processing times.

Whole code

<div class="ripple-loader">
  <div class="dot"></div>
  <div class="dot"></div>
  <div class="dot"></div>
  <div class="dot"></div>
  <div class="dot"></div>
</div>

<style>
.ripple-loader {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 60px;
}

.dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background-color: #6366F1;
  transform: scale(0);
  animation: ripple 1.5s linear infinite;
}

.dot:nth-child(2) {
  animation-delay: 0.2s;
}

.dot:nth-child(3) {
  animation-delay: 0.4s;
}

.dot:nth-child(4) {
  animation-delay: 0.6s;
}

.dot:nth-child(5) {
  animation-delay: 0.8s;
}

@keyframes ripple {
  0% {
    transform: scale(0);
    opacity: 0.8;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
  80% {
    transform: scale(0);
    opacity: 0.8;
  }
  100% {
    transform: scale(0);
    opacity: 0.8;
  }
}
</style>
      
Thank you for reading this article.

Comments

No comments yet. Be the first to comment!

More loaders

Similar

See also