Home / Snippets / Animation & Motion /
Spin
Continuous 360° rotation — loading spinners in two lines of CSS.
Quick implementation
@keyframes spin {
to { transform: rotate(360deg); }
}
.spin {
animation: spin 0.8s linear infinite;
}
/* Common spinner pattern */
.spinner {
width: 2rem;
height: 2rem;
border: 3px solid oklch(0.30 0.02 260);
border-top-color: oklch(0.72 0.19 265);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
.spin, .spinner { animation-duration: 1.5s; }
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building a loading indicator.
Goal: A CSS-only spinner using @keyframes rotate and a border trick — no JavaScript, no SVG.
Technical constraints:
- Use a single element with border: 3px solid + one transparent edge for the arc.
- Animation: rotate(360deg) with linear timing for constant speed.
- Use oklch() for all colors, not hex or rgba().
- Duration: 0.8s for a snappy feel.
- Include @media (prefers-reduced-motion: reduce) — slow the animation, don't remove it.
Framework variant (pick one):
A) Vanilla CSS class that works on any element.
B) React component — accept size and color props.
Edge cases to handle:
- Spinner must be centered in its container (use grid or flex parent).
- Reduced motion: slow to 1.5s instead of removing — users still need loading feedback.
- Size should be relative (rem) for accessibility zoom.
Return CSS.
Why this matters in 2026
Loading spinners are everywhere — buttons, page loads, data fetches. A CSS-only spinner needs no images, no SVG, no JavaScript animation frame. Two properties — a partial border and a rotation keyframe — create a universally recognized loading indicator.
The logic
The keyframe is minimal: to { transform: rotate(360deg); }. The browser infers from { transform: rotate(0deg); }. linear timing creates constant rotation speed — essential for spinners (easing would create an unnatural pause). The spinner appearance comes from a circle with one border color different from the others, creating a visible arc that rotates.
Accessibility & performance
For prefers-reduced-motion, slow the spinner rather than removing it — users still need loading feedback. A missing spinner is worse than a slow one. Add role="status" and aria-label="Loading" to the spinner element so screen readers announce the loading state. The rotation uses GPU compositing for zero-cost animation.