How CSS-only loaders work, and when to use them
Why keyframe spinners beat GIFs and SVGs for loading states, how transform animations stay smooth, and how to respect reduced motion.
Why a pure CSS loader beats a GIF or SVG
A spinning GIF is a separate file the browser must fetch, decode and cache, and it locks the animation to a fixed frame rate and a fixed color. An inline CSS loader ships as a handful of text rules inside a stylesheet you already download, so it costs no extra request and stays crisp at any size because it is drawn by the browser rather than sampled from pixels. It also inherits page styles, so you can recolor it or resize it by changing one number instead of exporting a new asset. For a small spinner shown during a fetch, the CSS version is almost always the lighter and more flexible choice.
Why the animations use transform and opacity
Each style animates only transform (rotate or scale) and, for the pulse, opacity. Those two properties are special because the browser can composite them on the GPU without recalculating layout or repainting the surrounding page. Animating width, height, top or margin instead would force the layout engine to run on every frame, which is the usual cause of a janky, stuttering spinner. Sticking to transform and opacity is the single most important habit for smooth loading animations, and it is why the generated keyframes never touch box dimensions once the element is sized.
How the wave effect is staggered
The dots and bars styles rely on three identical child spans that share one keyframe animation. What separates them is animation-delay: the second element starts a fraction of the cycle after the first, and the third starts twice that fraction later. With a one second cycle the bars offset by 0.125 and 0.25 seconds, so at any instant the three bars sit at different points of the same stretch animation. That constant phase difference is what your eye reads as a traveling wave rather than three elements moving together.
Accessibility and reduced motion
A loader is decorative to sighted users but invisible to a screen reader unless you label it, so wrap it in an element with role=status and an aria-label such as Loading. Continuous motion can also trigger discomfort for people with vestibular sensitivity, and the generated CSS animates unconditionally. To be considerate, guard the animation with a prefers-reduced-motion media query that pauses or simplifies it, for example by setting animation to none and showing a static dimmed shape when the user has asked the system to reduce motion. That small addition keeps the same visual for everyone else while respecting the setting.