Spinners and progress bars
<progress>
Chrome6
Edge12
Firefox6
Safari6
Features it needs
- <progress>Widely available
A progress element with a value draws a determinate bar, and the same element with the value removed draws the indeterminate one, which is the browser's own spinner. It carries the right role and reports its value to assistive technology without any aria being written by hand, which is the part the div-and-keyframes version usually gets wrong. Styling it is CSS on the element and its two pseudo-elements.
When this applies
Showing that work is happening, or how far along it is.
The native approach
<!-- Determinate. -->
<progress value="0.7">70%</progress>
<!-- Indeterminate: no value attribute at all. -->
<progress></progress>
<style>
progress { inline-size: 12rem; block-size: 0.5rem; }
/* The track and the filled part, in WebKit and Blink. */
progress::-webkit-progress-bar { background: #eee; }
progress::-webkit-progress-value { background: currentColor; }
</style>When the dependency is still right
An answer that always says "the platform covers it" is worse than no answer. These are the cases where this one does not hold.
- You need a circular ring. The element draws a bar, and the pseudo-elements that style it are not a shape you can bend into an arc, so a ring is still SVG or a conic-gradient on your own markup.
- The design is a branded multi-part animation, such as bouncing dots or a pulsing logo. Those are several moving elements and a progress element is one.
- You need a page-level loading bar tied to route changes, which is what nprogress is: the visual is trivial and the router integration and its timing are the library.
- Your styling has to match across engines exactly. The pseudo-elements differ between Blink, WebKit and Gecko, and accent-color only recolours the default rendering rather than restyling it.
Signs it was hand-rolled
No package is involved in any of these, so nothing would match in a package.json. If the code looks like one of them, this rule applies anyway, and the conditions above still decide.
- a div with a CSS keyframe rotation and a border-radius, standing in for a spinner, usually with no role or aria-label
- a wrapper div whose inline width is set to a percentage string to draw a filled bar