Chasing Dots Loader
A circular loader with glowing dots that chase each other around the center. It uses pure HTML and CSS with no JavaScript required.
<div class="chasing-dots-loader" aria-label="Loading">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
.chasing-dots-loader{
position:relative;
width:70px;
height:70px;
}
.chasing-dots-loader span{
position:absolute;
top:0;
left:50%;
width:10px;
height:10px;
margin-left:-5px;
border-radius:50%;
background:#22d3ee;
transform-origin:5px 35px;
animation:chasingDot 1.2s linear infinite;
}
.chasing-dots-loader span:nth-child(1){
transform:rotate(0deg);
animation-delay:0s;
}
.chasing-dots-loader span:nth-child(2){
transform:rotate(45deg);
animation-delay:-.15s;
}
.chasing-dots-loader span:nth-child(3){
transform:rotate(90deg);
animation-delay:-.30s;
}
.chasing-dots-loader span:nth-child(4){
transform:rotate(135deg);
animation-delay:-.45s;
}
.chasing-dots-loader span:nth-child(5){
transform:rotate(180deg);
animation-delay:-.60s;
}
.chasing-dots-loader span:nth-child(6){
transform:rotate(225deg);
animation-delay:-.75s;
}
.chasing-dots-loader span:nth-child(7){
transform:rotate(270deg);
animation-delay:-.90s;
}
.chasing-dots-loader span:nth-child(8){
transform:rotate(315deg);
animation-delay:-1.05s;
}
@keyframes chasingDot{
0%,100%{
opacity:.2;
box-shadow:none;
}
50%{
opacity:1;
box-shadow:0 0 14px #22d3ee;
}
}
How This Chasing Dots Loader Works
The Chasing Dots Loader is a CSS-only loading indicator built from one parent <div> and eight empty <span> elements. Each span becomes a small circular dot, and the dots are arranged around the center of a 70px square container. There is no JavaScript in this component, so the full effect comes from positioning, transforms, animation delays, opacity changes, and a temporary glow.
The .chasing-dots-loader container uses position: relative with a width and height of 70px. This gives the absolutely positioned dots a fixed reference area. Every span is placed at top: 0 and left: 50%, which initially positions each dot along the top-center of the container.
Each dot is 10px by 10px with border-radius: 50%, turning the square span into a circle. The cyan #22d3ee background gives all eight dots the same base color. A margin-left: -5px offsets each dot by half its width, keeping it correctly centered on the container’s horizontal midpoint.
The circular arrangement is created with transform-origin: 5px 35px. The first value places the transform origin at the horizontal center of the 10px dot, while the second moves that origin 35px downward. Since the loader itself is 70px tall, that point corresponds to the vertical center of the container. Rotating each span around this distant transform origin places the dots around an invisible circle.
The eight dots use rotations of 0deg, 45deg, 90deg, 135deg, 180deg, 225deg, 270deg, and 315deg. Because 360 degrees is divided evenly into eight 45-degree sections, the dots remain evenly spaced around the loader.
All dots run the same chasingDot animation for 1.2s with a linear timing function and an infinite loop. The animation itself does not move the dots around the circle. Their positions stay fixed. Instead, each dot becomes brighter and then fades again, creating the visual impression that a bright point is chasing the other dots around the ring.
At the beginning and end of the keyframes, opacity is .2 and box-shadow is removed. At the 50% point, opacity becomes 1 and a 0 0 14px #22d3ee shadow creates the cyan glow.
The chasing sequence comes from negative animation delays. The first dot starts at 0s, while each following dot is offset by another -.15s, ending with -1.05s on the eighth dot. These staggered starting points mean the dots reach their brightest state at different times even though they all use the same animation.
Negative delays are useful here because the loader appears to already be in motion as soon as it is displayed instead of waiting for each dot’s delay to pass. For more information about this behavior, see the MDN animation-delay documentation.
The outer element also includes aria-label="Loading", giving the visual indicator a short accessible description.
Customizing the Chasing Dots Loader
The loader can be adjusted by changing a few dimensions, timing values, and visual properties in the existing CSS.
- Change the
70pxwidth and height of.chasing-dots-loaderto adjust the overall loader size. - Modify the
10pxdot width and height to make each circle larger or smaller. - Replace
#22d3eein the background and glow with another color. - Adjust
transform-origin: 5px 35pxif you change the dot or container dimensions and want to alter the circle radius. - Change the
1.2sanimation duration to make the chasing sequence faster or slower. - Modify the
.15sdifference between animation delays to change the spacing of the glowing sequence. - Adjust the faded opacity of
.2if inactive dots should appear more or less visible. - Change the
14pxbox-shadow blur to make the active glow tighter or broader.
Where to Use the Chasing Dots Loader
This loader is suitable for interfaces that need an indefinite loading state without displaying exact completion progress.
- Dashboard widgets while data is being fetched.
- Form submission states while a request is processed.
- Modal dialogs waiting for asynchronous content.
- Full-page loading screens with a centered indicator.
- Cards or panels that load independently from the rest of the page.
- Compact app interfaces where a circular loader fits better than a horizontal progress bar.
For another circular loading style with a different visual structure, the Orbit Loader is a related CodeRipple component to consider. The Chasing Dots Loader is especially useful when you want continuous activity feedback without introducing JavaScript or a numeric progress value.
Frequently Asked Questions
Does the Chasing Dots Loader use JavaScript?
No. The component has no JavaScript. Its full loading effect is created with CSS positioning, rotation, opacity, box-shadow, keyframes, and animation delays.
Are the dots actually rotating around the loader?
No. Each dot stays in a fixed position created by its rotation and transform origin. The chasing effect comes from the dots brightening at different times.
Why does the loader use negative animation delays?
Negative delays make each dot begin at a different point within the same animation cycle. This creates the staggered glowing sequence immediately when the loader appears.
How are the eight dots spaced evenly around the circle?
Each span is rotated by an additional 45 degrees. Eight equal 45-degree steps cover the complete 360-degree circle.
The Chasing Dots Loader uses a small amount of markup and one shared CSS animation to create a clear circular activity indicator without scripting or complex movement logic.
