UIXHERO

Spinner(スピナー)

処理中・読み込み中を回転アニメーションで伝えるUIコンポーネント。Skeletonとの使い分け・遅延表示(点滅防止)・サイズと配色の設計・role=statusとaria-labelの実装を解説する。

2026年3月3日
更新: 2026年9月3日
15
by Dengen Yosho(DGYS)

処理中・読み込み中であることを回転で視覚的に伝えるUIコンポーネント。ボタン内・フォーム・ページ中央など様々な場所に配置して使われる。Skeleton(コンテンツ形状のプレースホルダー)と比べて実装が簡単だが、「何が来るか」をユーザーに予告できない点で使い所が限られる。

この記事を読むと、Skeleton・Progress Bar との使い分け・遅延表示による点滅防止・サイズ設計・role="status"aria-label の実装・prefers-reduced-motion 対応が自分でできるようになります。


1. UI例(Preview / Live)

このスピナーは、 GUNJO の Spinner 実装です。サイズ、ボタン内のインライン表示、領域のオーバーレイを確認できます(右上 Code で編集可)。

実装で見る(GunjoUI)

この部品を、デザインシステム GUNJO の実装で確かめられます。

2. 定義(Definition)

処理中・読み込み中を回転アニメーション(円弧のボーダーがくるくる回る)で視覚的に伝えるコンポーネント。CSSの border-radius: 50% + border-top-color + @keyframes spin で実装される最もシンプルなローディングUI。

Spinnerが適しているケース vs Skeleton が適しているケース

SpinnerSkeleton
コンテンツ形状がわかる✗ 不向き✅ 向いている
処理時間が短い(〜2秒)✅ 向いている△ 過剰
ボタン内・インライン✅ 向いている✗ 不向き
フィード・リスト✗ 不向き✅ 向いている

3. 使い分け(When to use / When NOT to use)

3.1 When to use

  • ボタンの処理中(送信・保存・削除の実行中)
  • 認証・API呼び出しの短い待機(〜2秒程度)
  • コンテンツ形状が事前に分からないデータ取得
  • オーバーレイで操作をブロックしながら処理中を示す

3.2 When NOT to use

  • コンテンツ形状が分かっている(カード・リスト・テーブル)→ Skeleton を使う
  • 100ms以下の処理 → 表示しない(点滅防止)
  • 進捗が計測できる処理 を使う

3.3 代替UI(Alternatives)

  • コンテンツ形状が分かっている → Skeleton(Loading記事参照)
  • 進捗が計測できる → Progress Bar
  • 処理完了の通知 → Toast / Alert

4. 設計判断の核(Decision Principles)

Spinnerの核は「遅延表示」——200ms以下の高速処理にSpinnerを即時表示すると、ローディングが一瞬点滅してUIが不安定に見える。処理完了より先にSpinnerが出てはいけない。

判断の優先順位:① 表示(200ms)→ ② Skeleton との使い分け → ③ サイズ選択 → ④ aria 対応

  • 200ms遅延してから表示するsetTimeout(() => setShowSpinner(true), 200) を設定し、200ms以内に処理が完了した場合は Spinner を表示しない。これで高速処理時の「チラつき」を防ぐ
  • サイズはコンテキストに合わせる:ボタン内は xs(12px)〜sm(16px)、セクション内は md(24px)〜lg(32px)、ページ全体は xl(48px)以上。小さすぎるSpinnerは見えにくく、大きすぎると圧迫感を与える
  • 色はコンテキストの主色を使う:青系ブランドなら青、暗い上なら白を使う。グレーはニュートラルな場面に使う

5. 状態設計(States)

5.1 必須状態(Required)

  • Visible(表示中):アニメーション回転
  • Hidden(非表示):処理完了後または200ms遅延前

5.2 条件付き状態(Conditional)

  • prefers-reduced-motion: reduce :アニメーションを止めて静的な表示にする

6. バリエーション設計(Variants)

バリアントサイズ用途
インライン(ボタン内)xs / smボタンの処理中
セクションmd / lgカードやモーダル内の読み込み
ページxlページ全体の初期ロード
オーバーレイlg / xlコンテンツを操作不能にしながら処理中

7. パターン集(Good / Bad / How to fix)

7.0 よく崩れる設計パターン(3つ)

  • 即時表示による点滅onClicksetLoading(true) を即時実行し、100ms以下で完了する処理にSpinnerが一瞬だけ表示される
  • ページ全体をSpinnerで覆う:リスト・カードなどコンテンツ形状が分かっているのに、ページ中央にSpinnerだけ表示してコンテンツが全く見えない(Skeletonを使うべき場面)
  • 複数のSpinnerが同時表示:ページに3〜4箇所の独立したSpinnerが同時に表示されて、どこに注目すべきか分からない

7.1 Bad(典型3つ)

  • setLoading(true) を即時実行し、APIが50msで返ってきてもSpinnerが表示される
  • ユーザー一覧ページでSkeletonを使わずSpinner1個だけ表示し、リスト形状が何も伝わらない
  • <div className="spinner" />rolearia-label もなく、スクリーンリーダーが処理中を認識できない

7.2 Good(対になる3つ)

  • useEffectconst t = setTimeout(() => setShowSpinner(true), 200); return () => clearTimeout(t) を実装し、200ms以内の完了はSpinnerを表示しない
  • ユーザー一覧ではアバター円 + 名前行 + 説明行の Skeleton を使い、データ取得中もレイアウトが崩れない
  • <div role="status" aria-label="読み込み中" className="spinner" /> で音声ユーザーに処理中を伝える

7.3 How to fix(手順)

  1. const [showSpinner, setShowSpinner] = useState(false) を追加
  2. useEffect(() => { if (!isLoading) { setShowSpinner(false); return; } const t = setTimeout(() => setShowSpinner(true), 200); return () => clearTimeout(t); }, [isLoading]) で遅延表示を実装
  3. <div role="status" aria-label="読み込み中" /> で AR 対応
  4. コンテンツ形状が分かる場所は Skeleton に置き換えを検討する

8. ルール(Must / Better)

Must(守らないと壊れる)

Better(品質が跳ねる)


9. アクセシビリティ要件(必須)

Screen Reader

<div role="status" aria-label="読み込み中">
  <!-- 視覚的なSpinnerアニメーション -->
  <span class="sr-only">読み込み中</span>
</div>

role="status"aria-live="polite" と同等。sr-only(visually hidden)テキストを含めるとスクリーンリーダーがより確実に読み上げる。

Motion / Animation

@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; opacity: 0.6; }
}

Tailwind では motion-reduce:animate-none クラスで対応できる。


10. 実装メモ(Implementation Notes)

  • Tailwind の animate-spin は CSS animation: spin 1s linear infinite と同等。border-t-[color] を付けた円形要素に適用するだけでSpinnerになる
  • lucide-reactLoader2 アイコン(animate-spin と組み合わせ)を使うと、カスタムCSSを書かずにデザイン統一されたSpinnerを実装できる
  • shadcn/ui には Spinner コンポーネントは含まれていないが、公式ドキュメントにCSSアニメーションベースの実装例が記載されている

11. 関連リンク


12. まとめ

Spinnerの設計で最重要なのは「遅延表示」と「Skeletonとの使い分け」です。迷ったら 4. 設計判断の核 に戻り、「200msの遅延表示があるか」「コンテンツ形状が分かるならSkeletonに変えるべきではないか」「role="status" があるか」の3点を確認してください。Spinnerはすべての待機に使う万能UIではなく、「コンテンツ形状が事前に分からない短い待機」に特化したコンポーネントです。

更新のお知らせ

サイトに載せていない実例や、新しい記事のお知らせはこちらで出しています。

読んだ内容を、自分の画面に当てるとき

UIXHEROは、記事を書くほかに、画面の検品・判定、デザインシステムの構築、実装と改善の伴走を受けています。何を頼めばいいか決まっていない段階の相談も、同じ窓口で受けます。

UIXHEROに頼めることを見る

※ 記事の内容についての質問や、書いてほしいテーマの要望も同じ窓口で受けています

記事をシェア

メールでお知らせを受け取る

最終更新: 2026年9月3日

この記事を書いた人

Dengen Yosho(DGYS)

Dengen Yosho(DGYS)

UI/UXデザイナー兼デザインエンジニア デザイン歴25年以上 情報設計〜UIデザイン〜React/TypeScriptによる実装までを一気通貫で担当 大手企業のDXプロジェクトや決済アプリ領域で、デザインリードとして改善と構築を経験 現在はフリーランスとして、プロダクトのUI/UX改善とデザインシステム構築を支援 長年の実務の中で感じてきたのは、 「良いUI」はセンスではなく、再現可能な判断の積み重ねであるということ UIXHEROは、 心理学や行動科学の知見を、現場で使える設計言語に翻訳するための場所 関心領域は「ユーザーの行動が変わるUI」 人の認知・注意・意思決定の構造を理解し、 “なぜそのUIが機能するのか”を言語化することを目指している

あわせて読みたい

この記事に関連する記事をご紹介します

Bar Chart(棒グラフ)

カテゴリごとの量を棒の長さで比べるチャート。ゼロ基線の扱い、並び順、縦横の選び方、しきい値の見せ方という設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
18

Donut Chart(ドーナツチャート)

中央をくり抜いた円で構成比を示すチャート。中央に置く値の選び方、円グラフとの使い分け、リングの太さ、凡例の作りという設計判断と、色だけに頼らないアクセシビリティ要件を解説する。

2026年8月27日
17

Gauge Chart(ゲージチャート)

1つの値を範囲の中に置いて示す半円のチャート。範囲の両端に意味があるかという条件、しきい値の帯の設計、色だけで良否を伝えない書き方という設計判断とアクセシビリティ要件を解説する。

2026年8月27日
16

もっと深く知りたいですか?

ここに掲載されていないトピックについても、リクエストがあれば解説記事を追加します。 わかりにくい点や、具体的な事例について知りたいことがあれば教えてください。

リクエストを送る