How to Make a Pure CSS Loader (Spinner, Dots and Progress Bar)
By Purely CSS · Published October 9, 2026
A pure CSS loader is a loading animation built from a few HTML elements and a CSS @keyframes rule, with no images and no JavaScript. You draw a shape, then animate its transform or opacity in an infinite loop. The three examples below are the most useful patterns, and each one is only a few lines.
1. A spinning ring loader
Draw a circle with border-radius: 50%, give it a light border, and color just one side with border-top-color. Rotating the element makes that colored side look like it is chasing around the ring.
The animation only changes transform, which the browser can run on the GPU, so it stays smooth even while the page is busy.
<div class="spinner" role="status" aria-label="Loading"></div>2. Three bouncing dots
Put three spans in a flex row and give each the same bounce animation. A small animation-delay on the second and third dot offsets them, which creates the wave.
<div class="dots" role="status" aria-label="Loading">
<span></span>
<span></span>
<span></span>
</div>3. An indeterminate progress bar
Use a track with overflow hidden and a bar inside it that slides across. Because the bar moves with translateX instead of changing its width, the animation does not force the page to re-layout.
<div class="bar" role="progressbar" aria-label="Loading"><i></i></div>Tips
- Animate transform and opacity rather than width, height or margin. They are cheaper and stay smooth.
- Add role="status" and an aria-label so screen readers announce that something is loading.
- Respect people who prefer less motion with a prefers-reduced-motion media query that slows or stops the animation.
Common questions
Can I make a loader without JavaScript?
Yes. A loader only needs HTML for the shape and a CSS @keyframes animation, with animation-iteration-count set to infinite.
Why is my CSS loader choppy?
Usually the animation changes a layout property such as width or margin. Animate transform and opacity instead so the browser can use the GPU.
How do I change the speed of a CSS loader?
Change the duration in the animation shorthand, for example 0.9s to 1.5s. A longer duration is slower.
Want more examples?
Browse the full collection of pure CSS loaders, or try your own code in the playground.