Arc Spinner

호 스피너

A partial arc whose length and rotation change together as it spins — the Material Design circular loader.

Also known as: Material spinnerCircular indeterminate
···
html
<div class="wrap" role="status" aria-live="polite">
  <svg class="arc" aria-hidden="true" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20" fill="none" stroke="var(--line)" stroke-width="4.5"/><circle class="ac" cx="25" cy="25" r="20" fill="none" stroke="var(--accent)" stroke-width="4.5" stroke-linecap="round"/></svg>
  <span class="cap">stroke-dasharray 스윕 + rotate</span>
</div>
css
.wrap{display:flex;flex-direction:column;align-items:center;gap:16px}
.arc{width:clamp(38px,12vmin,68px);height:clamp(38px,12vmin,68px);animation:arcrot 1.4s linear infinite}
.ac{stroke-dasharray:126;stroke-dashoffset:100;animation:arcdash 1.4s ease-in-out infinite}
@keyframes arcrot{to{transform:rotate(360deg)}}
@keyframes arcdash{0%{stroke-dashoffset:118}50%{stroke-dashoffset:30}100%{stroke-dashoffset:118}}
.cap{font-size:clamp(9px,2.4vmin,11px);color:var(--muted);letter-spacing:.02em}

The same indeterminate "still working" signal as a ring spinner, but because the arc's length itself grows and shrinks, it stays visually interesting longer than a ring that just spins at a constant rate. Once a task can report real progress, switch the same SVG circle to the determinate progress-ring instead.

Built with an SVG <circle> whose stroke-dasharray sets the full circumference, then a keyframe animates stroke-dashoffset to make the visible arc grow and shrink, while the wrapping container spins continuously with rotate. The overlap of changing length and rotation is what produces Material Design's signature loading animation.

Skip it for loads under 200ms, and prefer a skeleton for a long wait covering the whole screen. Give the wrapper role="status" and aria-live="polite", and hide the SVG with aria-hidden="true" since it's decorative. Under prefers-reduced-motion, you can simplify by freezing the arc length and keeping only a steady rotation.