本文へスキップ

ローディングスピナー

CSSだけで動く3種のローディング表現。回転リング・3点バウンス・バーのシマー。読み込み中を静かに伝える定番の見本。

プレビュー

自動再生

操作自動で再生されます。

使いどころ

最終的な見た目の形が読み込み前に分からない、または形を作るほどの規模ではない読み込みに向く。ボタン内の処理中表示、単体の画像・アイコンの差し替え、モーダルを開いた直後の一時的な待ちなど、占有する面積が小さく「とにかく処理中だ」とだけ伝われば十分な場面が対象になる。スケルトンローディングとは逆で、こちらは最終レイアウトの寸法を事前に確保しない(このサンプルの3種のローダーもコンテンツの形を模していない単なる記号)。そのため、カード一覧や記事一覧のように読み込み後の形が既に分かっている場所にスピナーだけを置くと、差し替え時に周囲のレイアウトがガクッと動きやすく、そこはスケルトンの方が体験がよい。また待ち時間が10秒を超えるような長い処理にスピナー単体を使うのも避けたい。回り続けるだけでは進捗が伝わらず不安を煽るため、割合が分かるなら進捗バー、分からないなら経過時間や文言を添えるべきである。

仕組み

3種類ともCSSアニメーションのみで完結し、JSは使っていない。リングはborderの上辺だけ色を変えた円をrotate(360deg)で回すオーソドックスな実装、3点バウンスは3つのspanにanimation-delayを0.15秒刻みでずらしてdot-bounceを適用し、波が伝わるような動きを作る。バー・シマーは実際の進捗を持たない不定形プログレスで、幅40%の帯をleft:-40%から100%へ動かしつつ中間でwidthを55%まで伸縮させ、詰まったり伸びたりする質感を出している。ここで注意すべきは、リングとドットはtransform(rotate/translateY)だけで動いているためコンポジタ処理で軽いのに対し、バーだけはleftとwidthというレイアウトに影響するプロパティを直接アニメーションさせている点で、性質が異なる。3つともrole=status aria-label=読み込み中をマークアップに最初から持たせてあり、どのバリエーションを選んでも読み上げの土台は揃っている。

実装の注意

バー・シマーのbar-slideはleftとwidthを直接動かしているためレイアウト再計算を伴い、リング・ドットに比べて描画コストが高い。一覧の各行にミニスピナーを大量に並べるような使い方をするなら、バーは避けてリングかドットにするか、バーの実装をtransform:translateX()+scaleX()に書き換えた方が安全。次に、このコンポーネントはCSSのみで完結しており、いつ実コンテンツに差し替えるかの判断はJS側の責任になる。スピナーを表示し続けたままタイムアウト処理を書き忘れると、ネットワーク障害時に永久に回り続けるスピナーだけが残る事故が起きやすい。また、同じページに複数のスピナーを置くとrole=status aria-label=読み込み中が同一文言で何個も存在することになり、スクリーンリーダーには区別のつかない読み込み中が連続で読み上げられる。文脈が異なるスピナーには具体的なaria-labelを付け直すべきである。

アクセシビリティ

3種すべてにrole=statusとaria-label=読み込み中が最初から付いているため、視覚アニメーションを見なくても状態変化がスクリーンリーダーに伝わる土台はできている。prefers-reduced-motionの分岐もすでに実装済みで、reduce設定ではリングとドットのanimationを完全に止め(回転・バウンスをやめて静止した見た目にする)、バーも動く帯をやめてleft:0; width:60%の静的な状態に固定している。これは同じ辞典のスケルトンローディングには無い対応で、動きを止めても読み込み中であるという意味自体はrole=statusが担うため、動きゼロでも情報は失われない好例になっている。実装上の注意点は、aria-labelは状態が変わらない限り再読み上げされないため、同じ読み込み中のまま長時間止まっているように見える処理では、進捗や経過時間をテキストとして追加し、その変化をaria-liveで伝える工夫を足すとよい。

調整して使う

3種は用途で選び分ける。リングは最小サイズで場所を取らないためボタン内や小さいアイコン枠向き、ドットはやわらかい印象でチャットの入力中表示などカジュアルな場面に合い、バーは横長のスペース(カードの下部やフォームの送信中表示)を埋めるのに向く。色はブランドカラーに差し替えつつ、背景側のトラック色とのコントラストを保つ。速度はリング0.8秒・ドット1.2秒・バー1.4秒が既定で、速くしすぎると安っぽく、遅くしすぎると止まって見えるため、この前後0.2〜0.3秒の範囲で調整するのが無難。バーは不定形プログレスの代わりに、実際の進捗値が取れる場面ではwidthを都度書き換える確定プログレスバーに転用でき、その場合はanimationではなくtransition:widthで滑らかに伸ばす形に変える。

コード(コピーして使えます)

<div class="stage" id="stage">
  <div class="loaders">
    <div class="loader-cell">
      <div class="ring" role="status" aria-label="読み込み中"></div>
      <span class="loader-label">リング</span>
    </div>
    <div class="loader-cell">
      <div class="dots" role="status" aria-label="読み込み中">
        <span></span><span></span><span></span>
      </div>
      <span class="loader-label">3点バウンス</span>
    </div>
    <div class="loader-cell loader-cell--wide">
      <div class="bar" role="status" aria-label="読み込み中"><span></span></div>
      <span class="loader-label">バー・シマー</span>
    </div>
  </div>
</div>

タグ

同じカテゴリ「マイクロ・フィードバック」のほかのパーツ

関連パーツ