25 CSS Spinners 01 / 25
Neon Arc CSS Spinner
A single glowing cyan arc rotates on a deep-dark background, with a luminous leading-edge dot that amplifies the neon effect via CSS drop-shadow filters.
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="sp-01">
<div class="sp-01__ring">
<div class="sp-01__track"></div>
<div class="sp-01__spinner">
<div class="sp-01__arc"></div>
<div class="sp-01__dot"></div>
</div>
</div>
</div> <div class="sp-01">
<div class="sp-01__ring">
<div class="sp-01__track"></div>
<div class="sp-01__spinner">
<div class="sp-01__arc"></div>
<div class="sp-01__dot"></div>
</div>
</div>
</div>.sp-01,.sp-01 *,.sp-01 *::before,.sp-01 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-01{
--bg:#0a0a0f;
--arc:#00f5ff;
--glow:rgba(0,245,255,0.4);
--track:rgba(0,245,255,0.12);
--size:72px;
--thickness:4px;
display:flex;
align-items:center;
justify-content:center;
min-height:100vh;
background:var(--bg);
font-family:system-ui,sans-serif;
}
.sp-01__ring{
position:relative;
width:var(--size);
height:var(--size);
}
.sp-01__track{
position:absolute;
inset:0;
border-radius:50%;
border:var(--thickness) solid var(--track);
}
/* The arc and dot-arm share one rotating parent so they move together */
.sp-01__spinner{
position:absolute;
inset:0;
animation:sp-01-spin 1s cubic-bezier(0.6,0.2,0.4,0.8) infinite;
}
.sp-01__arc{
position:absolute;
inset:0;
border-radius:50%;
border:var(--thickness) solid transparent;
border-top-color:var(--arc);
border-right-color:var(--arc);
filter:drop-shadow(0 0 8px var(--glow)) drop-shadow(0 0 16px var(--glow));
}
/* Leading-edge dot — a glowing tip at the LEADING END of the arc.
The arc is built from border-top + border-right, so visually it
spans ~135° (top-left corner) through 12 → 3 → ~225° (bottom-right
corner). The END of border-right is at the bottom-right corner of
the box (4:30 clock position), which is the LEADING tip during
clockwise rotation.
To position the dot at 4:30 on a 72×72 spinner: rotate 135° around
the center via transform: rotate(135deg) translateY(-r), where r =
(size/2 - thickness/2). Using a CSS custom property for r keeps
this responsive to --size + --thickness changes.
The dot is anchored at the spinner center (top:50%, left:50%) then
rotated outward by 135° (= 4:30 clock direction = the leading-end
of the arc), with translateY(-r) moving it to the arc's stroke
midline radius. Sized 1.75× the arc thickness for a visible glowing
tip without a chunky-bump look. */
.sp-01__dot{
position:absolute;
top:50%;
left:50%;
width:calc(var(--thickness) * 1.75);
height:calc(var(--thickness) * 1.75);
transform:translate(-50%, -50%) rotate(135deg) translateY(calc(var(--size) / -2 + var(--thickness) / 2));
background:var(--arc);
border-radius:50%;
box-shadow:0 0 8px var(--arc),0 0 16px var(--glow);
}
@keyframes sp-01-spin{
0%{transform:rotate(0deg)}
100%{transform:rotate(360deg)}
}
@media (prefers-reduced-motion: reduce){
.sp-01__spinner{animation:none}
} .sp-01,.sp-01 *,.sp-01 *::before,.sp-01 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-01{
--bg:#0a0a0f;
--arc:#00f5ff;
--glow:rgba(0,245,255,0.4);
--track:rgba(0,245,255,0.12);
--size:72px;
--thickness:4px;
display:flex;
align-items:center;
justify-content:center;
min-height:100vh;
background:var(--bg);
font-family:system-ui,sans-serif;
}
.sp-01__ring{
position:relative;
width:var(--size);
height:var(--size);
}
.sp-01__track{
position:absolute;
inset:0;
border-radius:50%;
border:var(--thickness) solid var(--track);
}
/* The arc and dot-arm share one rotating parent so they move together */
.sp-01__spinner{
position:absolute;
inset:0;
animation:sp-01-spin 1s cubic-bezier(0.6,0.2,0.4,0.8) infinite;
}
.sp-01__arc{
position:absolute;
inset:0;
border-radius:50%;
border:var(--thickness) solid transparent;
border-top-color:var(--arc);
border-right-color:var(--arc);
filter:drop-shadow(0 0 8px var(--glow)) drop-shadow(0 0 16px var(--glow));
}
/* Leading-edge dot — a glowing tip at the LEADING END of the arc.
The arc is built from border-top + border-right, so visually it
spans ~135° (top-left corner) through 12 → 3 → ~225° (bottom-right
corner). The END of border-right is at the bottom-right corner of
the box (4:30 clock position), which is the LEADING tip during
clockwise rotation.
To position the dot at 4:30 on a 72×72 spinner: rotate 135° around
the center via transform: rotate(135deg) translateY(-r), where r =
(size/2 - thickness/2). Using a CSS custom property for r keeps
this responsive to --size + --thickness changes.
The dot is anchored at the spinner center (top:50%, left:50%) then
rotated outward by 135° (= 4:30 clock direction = the leading-end
of the arc), with translateY(-r) moving it to the arc's stroke
midline radius. Sized 1.75× the arc thickness for a visible glowing
tip without a chunky-bump look. */
.sp-01__dot{
position:absolute;
top:50%;
left:50%;
width:calc(var(--thickness) * 1.75);
height:calc(var(--thickness) * 1.75);
transform:translate(-50%, -50%) rotate(135deg) translateY(calc(var(--size) / -2 + var(--thickness) / 2));
background:var(--arc);
border-radius:50%;
box-shadow:0 0 8px var(--arc),0 0 16px var(--glow);
}
@keyframes sp-01-spin{
0%{transform:rotate(0deg)}
100%{transform:rotate(360deg)}
}
@media (prefers-reduced-motion: reduce){
.sp-01__spinner{animation:none}
}How this works
The arc is a border-radius:50% element with two adjacent border sides coloured (border-top-color and border-right-color) and the remaining sides transparent. A filter:drop-shadow chain emits two layered glow halos, keeping the glowing effect entirely on the compositor without a box-shadow paint call.
The leading-edge dot is a separate small circle absolutely positioned at the top-center and shares the same @keyframes sp-01-spin animation so it tracks the arc tip precisely. A faint --track ring behind both layers provides the 360° guide rail visible at low opacity.
Customize
- Change the glow colour by editing
--arcand--glowcustom properties on.sp-01— both are cyan by default. - Adjust ring size with
--size(default72px) and stroke weight with--thickness(default4px). - Swap to a slower, more elegant spin by changing the duration from
1sto1.8sinsp-01-spin. - Remove the dot leading-edge for a minimal look by setting
.sp-01__dot { display:none }. - Use
cubic-bezier(0.4,0,0.6,1)instead of the current easing for a more mechanical feel.
Watch out for
filter:drop-shadowon a ring element can trigger GPU layer promotion — avoid stacking 20+ glowing rings on one page.- The arc tip dot uses
translateX(-50%)combined with rotation, which can appear slightly offset in Safari below v15 due to transform-origin rounding. - On high-refresh displays the
1sspin feels slow; test at0.7sfor 120 Hz contexts.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 69+ | 13+ | 62+ | 69+ |
drop-shadow filter is widely supported; no conic-gradient dependency.