7 Pure CSS1 with JSPublished 2026-10-03Free · no sign-up
Loading animations for every kind of wait: a spinner for short pauses, a skeleton for content that is on its way, a progress bar for page loads and a progress ring when you know the percentage. Each one tells screen readers that something is loading, and slows down or stops for visitors who prefer reduced motion.
The classic loading ring: a faint full circle with one bright arc spinning around it. It is a single element with role=status and a visually hidden label, so screen readers announce 'Loading' instead of nothing. Change the size with one variable.
Three dots that rise and fall one after another, the loader people read as 'someone is typing'. Each dot runs the same keyframes with a staggered delay, and the bounce uses transform so it never triggers layout. Fits inside chat bubbles and buttons.
A placeholder that has the shape of the content that is coming: avatar, two text lines and a block, with a soft shimmer passing over them. Skeletons make waiting feel shorter than a spinner and stop the page jumping when the real content arrives, as long as they match its size.
A thin bar for page or upload loading when you do not know how long it will take. A highlight slides across the track on a loop. It uses the native progress element with no value, which browsers already expose as busy, and only restyles it.
A solid dot with rings that grow and fade outward, like a radar ping. It works as a loader, a 'live' indicator or a hotspot marker on a product image. Two pseudo-elements with offset delays make the rings, so the markup is one element.
Five bars that rise and fall like an audio equalizer. It suits media players, voice notes and anything to do with sound. Each bar scales from the bottom with transform-origin, so the motion stays smooth and the overall size never changes.
A circular progress indicator with the percentage in the middle, for uploads and multi-step tasks where you know how far along you are. The ring is an SVG circle whose stroke-dashoffset follows the value, and the element exposes role=progressbar with aria-valuenow so assistive tech reads the number.
document.querySelectorAll('.ttl-pr').forEach(function (el) {
var fill = el.querySelector('.ttl-pr-fill');
var num = el.querySelector('.ttl-pr-num');
var full = 2 * Math.PI * 52;
var value = 0;
function set(v) {
fill.style.strokeDashoffset = full * (1 - v / 100);
num.textContent = v + '%';
el.setAttribute('aria-valuenow', v);
}
setInterval(function () {
value = value >= 100 ? 0 : Math.min(100, value + 7);
set(value);
}, 400);
});
08. Orbit Loader
Pure CSS
Two small planets orbiting a centre point at different speeds and in opposite directions. It is a decorative loader for splash screens and empty states where a little personality fits. Each orbit is a rotating ring with a dot placed on its edge.
Under about a second, show nothing; a flash of spinner feels slower than no feedback. For one to three seconds, a small spinner or dots is enough. For content that is loading, such as a feed or a product grid, use a skeleton in the shape of that content. When you know how far along a task is, show real progress with a bar or ring.
Making loaders accessible
A spinning circle means nothing to a screen reader unless you say what it is. Give the loader role="status" and a label such as "Loading", or use a native <progress> element. For known progress, role="progressbar" with aria-valuenow lets assistive technology read the number.
Keeping animations smooth
Every loader here animates only transform and opacity, which the browser can run on the GPU without recalculating the page layout. That keeps them smooth even while the main thread is busy loading the thing you are waiting for. Each one also has a prefers-reduced-motion rule that slows or removes the motion.
How to use these demos
Each loader is scoped with a .ttl- class prefix. Show it while your request is pending and remove it, or swap it for the content, when the request finishes. Open any loader in the editor to change its size and colours with a live preview.
Frequently asked questions
Are pure CSS loaders better than GIFs?
Usually, yes. They are a few hundred bytes instead of kilobytes, stay sharp at any size and screen density, and you can recolour them with one line of CSS.
Do these loaders affect page speed?
Barely. They are tiny and animate only transform and opacity, so they do not cause layout work. A skeleton that matches the final content size also prevents layout shift when the content arrives.
Can I change the colours?
Yes. Each loader uses two or three hex colours. Replace them with your brand colours, or open the loader in the editor and change them with a live preview.