호 스피너

Arc Spinner

원의 일부(호)만 그려서 그 길이와 회전이 함께 바뀌며 도는, 머티리얼 디자인식 로더.

다른 이름: 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}

링 스피너와 같은 비확정적 "처리 중" 신호지만, 호의 길이 자체가 늘었다 줄었다 하기 때문에 일정한 속도로만 도는 단순한 링보다 더 오래 봐도 지루하지 않습니다. 진행률을 실제로 알 수 있는 작업이라면 같은 SVG 원을 확정적으로 쓰는 progress-ring으로 바꾸세요.

SVG <circle>의 stroke-dasharray로 전체 둘레를 정하고 stroke-dashoffset을 keyframe으로 움직여 보이는 호의 길이를 짧게-길게 반복시키는 동시에, 감싸는 컨테이너 전체를 rotate로 계속 돌립니다. 길이 변화와 회전이 겹치면서 머티리얼 디자인의 시그니처 로딩 애니메이션이 만들어집니다.

200ms 이내로 끝나는 로딩이면 아예 생략하고, 화면 전체를 가리는 긴 대기라면 스켈레톤을 우선 검토하세요. 감싸는 요소에 role="status"·aria-live="polite"를 주고 SVG는 장식이므로 aria-hidden="true"로 숨깁니다. prefers-reduced-motion에서는 호 길이 변화를 멈추고 일정한 회전만 남기는 식으로 단순화할 수 있습니다.