← Back to gallery
CSS

Conic-gradient Spinner

A single-element spinner — conic-gradient paints the arc, a radial mask thins the ring without SVG. Three variants: a single quarter arc, balanced dual arcs, and a tapered segmented trace.

spinnerloaderconic-gradientradial-masksingle-elementrotateprefers-reduced-motion

Spinner / conic-gradient / mask

Conic-gradient spinner

Reimplements the CSS spinner with a conic-gradient arc and a radial mask so the ring stays thin without SVG, GIF, or border tricks. Three variants — single quarter arc, balanced dual arcs, and a tapered segmented trace.

Single accent arc + radial mask

Quarter Arc

A conic-gradient paints one bright 90° arc and a transparent remainder. A radial mask carves the center out so the arc rides a clean ring.

  • quarter arc
  • radial mask
  • single loop

Two opposing arcs + uniform speed

Dual Arc

A second arc sits 180° opposite the first. Both share the same hue so the spin reads as a balanced orbit rather than a single head.

  • dual arc
  • balanced orbit
  • panel-scale

Tapered hue stops + slow sweep

Segmented Trace

Multiple color stops inside the conic fade the arc across its span. The slower duration leans into an ambient look for long-running jobs.

  • trace
  • ambient speed
  • gradient edge

Arc inspector

Quarter Arc

  • quarter arc
  • radial mask
  • single loop

A conic-gradient paints one bright 90° arc and a transparent remainder. A radial mask carves the center out so the arc rides a clean ring. The ring rotates as a whole; because only the arc is colored, the spinner reads as a moving indicator instead of a filled wheel.

Helped you ship something? 🐟 Send my cat a churu

.conic-ring {
  width: 96px;
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    conic-gradient(from 180deg, rgba(103, 232, 249, 0.98) 0deg 90deg, rgba(103, 232, 249, 0) 90deg 360deg),
    rgba(103, 232, 249, 0.18);
  background-repeat: no-repeat;
  -webkit-mask: radial-gradient(
    circle at center,
    transparent calc(50% - 18% - 0.5px),
    black calc(50% - 18%)
  );
  mask: radial-gradient(
    circle at center,
    transparent calc(50% - 18% - 0.5px),
    black calc(50% - 18%)
  );
  animation: conicSpin 1.10s linear infinite;
}

@keyframes conicSpin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .conic-ring { animation: none; }
}

How to make this

A CSS conic-gradient spinner paints a partial conic arc, cuts the center out with a radial mask, and rotates the ring while nearby text carries the loading status.

html
1<span class="conic-spinner" aria-hidden="true"></span><span class="conic-spinner-label">Loading preview</span> <style>.conic-spinner {  width: 4rem;  aspect-ratio: 1;  display: inline-block;  border-radius: 50%;10  background:    conic-gradient(from 180deg,      #67e8f9 0deg 92deg,      rgba(103, 232, 249, 0) 92deg 360deg),    rgba(103, 232, 249, .16);15  -webkit-mask: radial-gradient(    circle at center,    transparent calc(50% - .52rem),    #000 calc(50% - .5rem)  );  mask: radial-gradient(    circle at center,    transparent calc(50% - .52rem),    #000 calc(50% - .5rem)  );25  animation: conic-spinner-recipe-spin 1.1s linear infinite;}27.conic-spinner-label {  display: inline-block;  margin-inline-start: .65rem;  color: #cbd5e1;  font: 600 .9rem/1.2 ui-sans-serif, system-ui;}@keyframes conic-spinner-recipe-spin {  to { transform: rotate(1turn); }}36@media (prefers-reduced-motion: reduce) {  .conic-spinner { animation: none; }}</style>

Annotated snippet

  1. Line 1The spinner itself is decorative, so hide it from assistive technology. Put the loading message in nearby text or a live region when the state needs to be announced.
    PitfallShould a CSS spinner announce loading by itself?

    No. The visual ring should usually be aria-hidden. Put the loading status in adjacent text, aria-busy on the affected region, or a polite live region if the state change needs announcement.

  2. Line 10The first background layer paints the moving arc. Leave most of the conic gradient transparent so the spinner reads as a head moving around a ring instead of a filled wheel.

    Same masked ring, same rotation animation. A full uniform ring (360°) looks static while spinning — every angle looks the same. A narrow 92° head leaves the rest transparent so the eye catches the moving leading edge.

  3. Line 15The radial mask cuts out the center and turns the conic fill into a ring. Without this mask, the same gradient becomes a pie slice.

    A conic gradient alone is a filled disk; the radial mask turns it into a spinner ring.

    PitfallWhy does my conic-gradient spinner look like a pie chart?

    The center has not been masked out. Add a radial mask with a transparent center and opaque outer band so the conic gradient becomes a ring.

  4. Line 25Rotate the whole ring, not the gradient stops. The paint stays static on the element while transform handles the motion.
    PitfallIs a conic-gradient spinner performant?

    A single transformed element is cheap. Performance drops when many large masked gradients or filtered glow layers spin at once, so keep loader rings small and avoid stacking blur-heavy effects.

  5. Line 27The label is separate from the spinner. This keeps the status readable when animation is disabled and avoids making a purely visual ring carry meaning.
    PitfallShould a CSS spinner announce loading by itself?

    No. The visual ring should usually be aria-hidden. Put the loading status in adjacent text, aria-busy on the affected region, or a polite live region if the state change needs announcement.

  6. Line 36Reduced motion stops the indefinite spin. Keep the static ring and the text label visible so loading state remains understandable.
    PitfallWhat should prefers-reduced-motion do for spinners?

    Stop indefinite rotation and leave a static indicator plus readable status text. Do not hide the loading state entirely; motion preference should affect movement, not information.

Other pitfalls

Is conic-gradient supported across browsers?
Modern Chromium, Firefox, and Safari support conic-gradient. For older browsers, provide a border spinner, SVG spinner, or static fallback; keep the loading text independent of the visual treatment.
Advanced

Taper the arc head with multi-stop opacity — a comet trail instead of a hard pie wedge

Same 1.4s rotation, same radial mask, same #67e8f9 leading-edge brightness. BEFORE uses two hard stops — the 92° head is uniformly full opacity, the rest is fully transparent. The result reads as a pie wedge that just happens to be rotating; the eye locks onto BOTH edges equally. AFTER keeps the same 92° span but adds intermediate stops that fade the cyan from 100% at the leading edge down to 0% at the tail. Now the eye reads a bright head with a softer trail behind it — a comet, not a pie slice.

View explanation and full code18 lines

The base conic-gradient paints a solid 92° arc of #67e8f9 over transparent — it works, but the leading and trailing edges are abrupt, so the spinner reads as "rotating pie slice" rather than "moving head with a trail behind it". Real production spinners taper the head so the leading edge stays bright while the trailing portion fades. Same conic-gradient property, same mask, same rotation animation — just richer color stops inside the head: 100% opacity at the leading edge, then several stops fading to transparent across the 92° span. The change is purely additional stops in the same gradient declaration.

Append these rules inside the <style> block from the base snippet above.

css
/* Advanced: tapered arc head — extends the base recipe.   Same conic-gradient property, same radial mask cut-out, same   rotation animation. The arc head now contains multiple stops that   fade the cyan opacity from 100% at the leading edge down to 0% at   the tail, producing a "comet trail" look rather than a hard pie   wedge. No structural change — just denser color stops in the same   gradient. */.conic-spinner {  background:    conic-gradient(from 180deg,      rgba(103, 232, 249, 1)   0deg,      rgba(103, 232, 249, .85) 30deg,      rgba(103, 232, 249, .55) 60deg,      rgba(103, 232, 249, .25) 80deg,      rgba(103, 232, 249, 0)   92deg,      rgba(103, 232, 249, 0)   360deg),    rgba(103, 232, 249, .16);}

Notes

Overview

Conic-gradient spinners paint a rotating arc with one CSS property and one element — no SVG, no GIF, no border tricks. A conic-gradient colors a single bright arc and a transparent remainder; a radial-gradient mask carves the centre out so the spinner reads as a ring. The whole element rotates on a linear keyframe.

When to use it

Reach for conic spinners on form-submit loading states, async page transitions, and anywhere a small indeterminate progress indicator needs to fit inside a button or chip. Skip them for long-running operations — a spinner is an unresolved promise; users tolerate it for seconds, not minutes. Use a determinate progress bar past that point.

How it works

The element gets background: conic-gradient(from 0deg, transparent 270deg, var(--accent) 360deg) — a 90-degree bright arc with transparent remainder. To carve out the center, apply mask: radial-gradient(circle, transparent 60%, black 61%) which hides the inner disc and leaves only an outer ring. Then animation: spin 1s linear infinite with a @keyframes spin { to { transform: rotate(360deg) } } rule rotates the whole element. Linear timing is non-negotiable — ease curves make spinners look like they are hesitating.

Production gotchas

Spinning a background-only element rotates the gradient too — this is what you want. But spinning a layered element with an internal label or icon also rotates the label; either keep the spinner as a leaf element or counter-rotate the inner content. The CSS mask property still needs the -webkit-mask prefix for Safari iOS as of 2026. Hard-edged mask transitions can banding on retina; use black 61% rather than black 60.1% for the cut-off — a wider transition smooths the edge.

Accessibility

Wrap the spinner in a container with role="status" + aria-label="Loading" so screen readers announce its presence. Under prefers-reduced-motion: reduce swap the infinite spin for a single static frame — the visual indicator still shows “working” without the continuous rotation that can trigger vestibular issues. Avoid spinners shorter than 600ms per revolution; faster rates feel anxious.

References

Implementation depth

A conic-gradient spinner is strongest as a single-element loader. The gradient paints the arc, a radial mask cuts the hole, and transform rotation supplies motion without SVG markup.

Spinners communicate waiting, not progress. Use them for unknown durations, prefer native progress for known values, and stop rotation under reduced motion while keeping a static loading indicator visible.