Gradient Ring
Ring of 50 px — conic gradient transparent→#6366f1, centre masked by ::before at inset 5 px (fixed background #0a0a0f) — 1 rev/s linear, zero JS.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Loaders has 29 effects, including 4 free. Explore the category →
3 usage examples



How it works
Structure. A single div.loader-gradient-ring of 50 × 50 px, border-radius: 50%. Its background: conic-gradient(transparent, #6366f1) — the conic gradient sweeps 360° clockwise from 0° (top), from transparent to indigo, painting a disc whose colour gradually thickens. The ::before pseudo-element (content: ""; position: absolute; inset: 5px; background: #0a0a0f; border-radius: 50%) lays a 40 × 40 px disc over the centre, masking it: only the outer 5 px ring remains visible. No JavaScript, no dependencies.
Animation. @keyframes ringRotate { to { transform: rotate(360deg) } }, applied as animation: 1s linear 0s infinite. The disc spins at constant speed — one full revolution per second. The conic gradient rotates with it: the fully opaque zone leads, the transparent zone closes the circle. Measured in Chromium: the transform matrix confirms approximately 90° of rotation in 250 ms — a quarter turn per quarter second, infinite loop with no drift.
Integration constraint. The ::before background is hard-coded to #0a0a0f, the colour of the demo wrapper .demo-preview. Outside that wrapper, on any different background, the central mask stays dark and becomes visible: the ring then looks like a coloured disc with a dark centre rather than a transparent ring. To fix this, replace background: #0a0a0f on .loader-gradient-ring::before with the exact colour of the containing surface.
Accessibility
- prefers-reduced-motion not handled: no
@media (prefers-reduced-motion: reduce)rule in the sold code. Measured under reduced-motion emulation:playState: "running", the rotation continues. Add at minimum@media (prefers-reduced-motion: reduce) { .loader-gradient-ring { animation-duration: 10s } }to slow it considerably, oranimation: noneto stop it. - role="status" absent: the ring is silent for screen readers. For a loading indicator, set
role="status"(orrole="progressbar") on the element witharia-label="Loading…", or insert a visually hidden child text (.sr-only). - aria-busy / aria-live absent: the ring does not announce the end of loading. Best practice is to set
aria-busy="true"on the container that is loading (not on the ring itself) and remove it once the content is ready. The ring remains a visual-only indicator. - If the ring is used as pure decoration with no semantic role, add
aria-hidden="true"todiv.loader-gradient-ringso assistive technologies ignore it — and delegate the loading notification to an existingaria-liveregion in the page.
Browser compatibility
Two properties set the floor: conic-gradient (Chrome 69, Firefox 83, Safari 12.1) and the inset shorthand (Chrome 87, Firefox 87, Safari 14.1 — more restrictive). Zero JavaScript, zero dependencies.
Without conic-gradient (IE, browsers before 2018): transparent background, ring invisible. Without inset (Chrome 69–86, Firefox 61–86): the ::before mask does not position correctly, the conic gradient appears as a spinning full disc. In both cases, a classic border spinner is the natural fallback.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="loader-gradient-ring"></div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Outer diameter (CSS — width: 50px; height: 50px) |
50 px | Total ring size. Change both values together. 20–24 px: fits in a button or bubble. 60–80 px: zone-level indicator. |
Ring thickness (CSS — inset: 5px on ::before) |
5 px (inner diameter = 50 − 2×5 = 40 px) | Gap between the outer edge and the centre mask. 3px: thin ring. 8px: thick ring, more legible at small sizes. |
Mask background (CSS — background: #0a0a0f on ::before) |
#0a0a0f | Must exactly match the container background. White: #ffffff. Shared CSS variable: var(--surface). Any mismatch makes the mask visible as a dark disc. |
Arc colour (CSS — conic-gradient(transparent, #6366f1)) |
#6366f1 (indigo) | Replace #6366f1 with any colour. The start remains transparent. For an arc that begins already coloured (no invisible zone): conic-gradient(#6366f199, #6366f1). |
Rotation speed (CSS — first value of animation) |
1s | 0.6s: fast, urgent feel. 2s: slow, background-level indicator. Perceived speed also depends on arc length: a longer arc reads as faster. |
Timing (CSS — linear) |
linear | Standard for a spinner. ease-in-out gives a slight ease on each revolution — organic but unconventional for a loading indicator. |
Rotation direction (CSS — animation-direction) |
normal (clockwise) | animation-direction: reverse for counter-clockwise. Some interfaces use counter-clockwise for cancel or unload spinners. |
FAQ
::before background is hard-coded to #0a0a0f — the demo wrapper colour. On any other background the mask stays dark and becomes visible. Fix: replace background: #0a0a0f on .loader-gradient-ring::before with your exact surface colour. If the ring appears on several different surfaces, a shared CSS variable (--ring-bg: your-colour) avoids editing multiple rules.conic-gradient(transparent, #6366f1)) produces a full-circle fade: roughly a quarter of the ring is nearly invisible. For a solid arc over 270° followed by a 90° transparent tail, use conic-gradient(#6366f1 0deg 270deg, transparent 270deg 360deg). For hard edges with no fade: conic-gradient(#6366f1 270deg, transparent 270deg).border: 4px solid with three indigo sides and one transparent side — a uniform ring with a clean gap, single HTML element, no mask. fx-0435 paints the gradient directly onto the disc background via conic-gradient and masks the centre with ::before: the colour varies continuously from transparent to full, with no gap. The border technique cannot produce an angular gradient; the conic-gradient technique supports any angular palette but requires the mask background to match the containing surface.