CSSだけで作るローディングアニメーション|コピペで使える5種類と、見る人への配慮

CSSだけで作るローディングアニメーション コピペで使える5種類と、見る人への配慮

ページの読み込み中に出てくる、くるくる回る輪や、順番に跳ねる点。あの動きは、CSSだけで作れます。JavaScriptは要りません。

使う部品は、動きの台本を書く @keyframes(アット・キーフレームズ)と、その台本を部品に割り当てる animation(アニメーション)の2つです。回す・動かす・伸ばすは transform(トランスフォーム)が受け持ちます。

この記事では、よく使う5種類のローディングを、動く見本とコピペ用のコードで紹介します。仕組みの説明、数値を変えたときの違い、動きが苦手な人への配慮まで、順番に見ていきます。

トミー

連載「WEBの技術」では、CSSでできる表現を、動く見本つきで紹介していきます。
1回目は、どのサイトにも出番があるローディングから始めます。

完成見本:CSSだけで作った5種類のローディング

どれも、ページを開いた時点から動いています。マウスを乗せたり、タップしたりする必要はありません。

SPINNER1. 回る輪
BOUNCING DOTS2. 跳ねる3つの点
BARS3. 伸び縮みする棒
MORPHING SQUARE4. 形を変えながら回る四角
TEXT5. 順番に色づく文字

※ スマホやパソコンで「動きを減らす」設定をオンにしている方には、回ったり跳ねたりせず、ふわっと明るさが変わる形で表示されます。理由は後半の「見る人への配慮」で説明します。

コピペ用のコード

見本ごとに、HTMLとCSSを並べました。HTMLはローディングを出したい場所に、CSSはサイトのCSSファイルや、WordPressならテーマの「追加CSS」などに入れます。

クラス名の頭に付けた kd-ld- は、サイトのほかのデザインと名前がぶつからないようにするための目印です。変えてもかまいません。変えるときは、HTMLとCSSの両方を同じ名前にそろえてください。

どのコードにも入っている role="status" と kd-ld-sr は、読み上げソフトに「読み込み中」を伝えるための部分です。色の #0284C7 は、白い背景で見やすい濃さにした青です。どちらも理由は後半で説明します。

1. 回る輪

いちばんよく見る「くるくる」です。輪の上だけ色を変えて、全体を回しています。どんなサイトにもなじみます。

読み込み中
動く見本
HTML
<div role="status" aria-live="polite">
  <span class="kd-ld-ring" aria-hidden="true"></span>
  <span class="kd-ld-sr">読み込み中</span>
</div>
CSS
.kd-ld-ring {
  display: inline-block;
  box-sizing: border-box;
  width: 48px;
  height: 48px;
  border: 5px solid #E0F2FE;
  border-top-color: #0284C7;
  border-radius: 50%;
  animation: kd-ld-spin 0.9s linear infinite;
}
@keyframes kd-ld-spin {
  to { transform: rotate(360deg); }
}
/* 動きを減らす設定の人には、回さずに明滅だけ */
@media (prefers-reduced-motion: reduce) {
  .kd-ld-ring { animation: kd-ld-fade 2s ease-in-out infinite; }
}
@keyframes kd-ld-fade {
  50% { opacity: 0.35; }
}
/* 画面には出さず、読み上げソフトには文字として残す */
.kd-ld-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

2. 跳ねる3つの点

点が順番に跳ねます。チャットの「入力中」のような、やわらかい印象になります。

読み込み中
動く見本
HTML
<div class="kd-ld-dots" role="status" aria-live="polite">
  <span class="kd-ld-dot" aria-hidden="true"></span>
  <span class="kd-ld-dot" aria-hidden="true"></span>
  <span class="kd-ld-dot" aria-hidden="true"></span>
  <span class="kd-ld-sr">読み込み中</span>
</div>
CSS
.kd-ld-dots {
  display: inline-flex;
  align-items: flex-end;
  gap: 8px;
  height: 40px;
}
.kd-ld-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #0284C7;
  animation: kd-ld-bounce 0.5s ease-in-out infinite alternate;
}
.kd-ld-dot:nth-child(2) { animation-delay: 0.15s; }
.kd-ld-dot:nth-child(3) { animation-delay: 0.3s; }
@keyframes kd-ld-bounce {
  to { transform: translateY(-18px); }
}
@media (prefers-reduced-motion: reduce) {
  .kd-ld-dot { animation: kd-ld-fade 2s ease-in-out infinite; }
}
@keyframes kd-ld-fade {
  50% { opacity: 0.35; }
}
/* 画面には出さず、読み上げソフトには文字として残す */
.kd-ld-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

3. 伸び縮みする棒

5本の棒が、波のように順番に伸び縮みします。音や動画を扱うページと相性のいい形です。

読み込み中
動く見本
HTML
<div class="kd-ld-bars" role="status" aria-live="polite">
  <span class="kd-ld-bar" aria-hidden="true"></span>
  <span class="kd-ld-bar" aria-hidden="true"></span>
  <span class="kd-ld-bar" aria-hidden="true"></span>
  <span class="kd-ld-bar" aria-hidden="true"></span>
  <span class="kd-ld-bar" aria-hidden="true"></span>
  <span class="kd-ld-sr">読み込み中</span>
</div>
CSS
.kd-ld-bars {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 44px;
}
.kd-ld-bar {
  width: 7px;
  height: 100%;
  border-radius: 4px;
  background: #0284C7;
  animation: kd-ld-stretch 1s ease-in-out infinite;
}
/* マイナスの待ち時間=開いた瞬間から、途中の形で動き出す */
.kd-ld-bar:nth-child(1) { animation-delay: -0.5s; }
.kd-ld-bar:nth-child(2) { animation-delay: -0.4s; }
.kd-ld-bar:nth-child(3) { animation-delay: -0.3s; }
.kd-ld-bar:nth-child(4) { animation-delay: -0.2s; }
.kd-ld-bar:nth-child(5) { animation-delay: -0.1s; }
@keyframes kd-ld-stretch {
  0%, 100% { transform: scaleY(0.35); }
  50%      { transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
  .kd-ld-bar { animation: kd-ld-fade 2s ease-in-out infinite; }
}
@keyframes kd-ld-fade {
  50% { opacity: 0.35; }
}
/* 画面には出さず、読み上げソフトには文字として残す */
.kd-ld-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

4. 形を変えながら回る四角

角の丸い四角が、半回転するあいだに丸になり、また四角に戻ります。ブランドの色を1つだけ見せたいときに向いています。

読み込み中
動く見本
HTML
<div role="status" aria-live="polite">
  <span class="kd-ld-square" aria-hidden="true"></span>
  <span class="kd-ld-sr">読み込み中</span>
</div>
CSS
.kd-ld-square {
  display: inline-block;
  width: 36px;
  height: 36px;
  border-radius: 6px;
  background: #0284C7;
  animation: kd-ld-turn 1.6s ease-in-out infinite;
}
@keyframes kd-ld-turn {
  0%   { transform: rotate(0deg); }
  50%  { transform: rotate(180deg); border-radius: 50%; }
  100% { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .kd-ld-square { animation: kd-ld-fade 2s ease-in-out infinite; }
}
@keyframes kd-ld-fade {
  50% { opacity: 0.35; }
}
/* 画面には出さず、読み上げソフトには文字として残す */
.kd-ld-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

5. 順番に色づく文字

「読み込み中」の1文字ずつが、順番に色づいて少し浮きます。文字なので、何を待っているのかがそのまま伝わります。

読み込み中
動く見本
HTML
<div class="kd-ld-text" role="status" aria-live="polite">
  <span class="kd-ld-char" aria-hidden="true">読</span>
  <span class="kd-ld-char" aria-hidden="true">み</span>
  <span class="kd-ld-char" aria-hidden="true">込</span>
  <span class="kd-ld-char" aria-hidden="true">み</span>
  <span class="kd-ld-char" aria-hidden="true">中</span>
  <span class="kd-ld-sr">読み込み中</span>
</div>
CSS
.kd-ld-text {
  display: inline-flex;
  gap: 2px;
  font-size: 24px;
  font-weight: 700;
  color: #64748B;
}
.kd-ld-char {
  display: inline-block;
  animation: kd-ld-glow 1.5s ease-in-out infinite;
}
.kd-ld-char:nth-child(2) { animation-delay: 0.15s; }
.kd-ld-char:nth-child(3) { animation-delay: 0.3s; }
.kd-ld-char:nth-child(4) { animation-delay: 0.45s; }
.kd-ld-char:nth-child(5) { animation-delay: 0.6s; }
@keyframes kd-ld-glow {
  0%, 50%, 100% { color: #64748B; transform: translateY(0); }
  25%           { color: #0284C7; transform: translateY(-4px); }
}
/* 動きを減らす設定の人には、浮かせずに色だけ */
@media (prefers-reduced-motion: reduce) {
  .kd-ld-char { animation-name: kd-ld-color; }
}
@keyframes kd-ld-color {
  25% { color: #0284C7; }
}
/* 画面には出さず、読み上げソフトには文字として残す */
.kd-ld-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

仕組み:動きは3つの部品でできている

5種類とも、使っている部品は同じです。「台本」「再生のしかた」「動かし方」の3つに分けると分かりやすくなります。

@keyframes:動きの台本

@keyframes は、「どの時点で、どんな見た目にするか」を書く台本です。0% が始まり、100% が終わり。from と to は、0% と 100% の言いかえです。

@keyframes kd-ld-spin {
  to { transform: rotate(360deg); }
}

回る輪の台本は、「終わり(to)に360度回っている」の1行だけです。始まりを書いていないときは、部品のもとの見た目(回っていない状態)が始まりとして使われます。あいだの動きは、ブラウザが自動で埋めてくれます。

animation:台本を、何秒で・何回

台本を書いただけでは動きません。animation で、「どの台本を・何秒で・どんな速さで・何回」再生するかを決めます。

animation: kd-ld-spin 0.9s linear infinite;
書いたもの意味もとのプロパティ名
kd-ld-spin使う台本の名前animation-name
0.9s1回分にかける時間(0.9秒)animation-duration
linear速さの変え方(ずっと同じ速さ)animation-timing-function
infiniteくり返す回数(ずっと)animation-iteration-count

animation は、こうした指定をまとめて1行で書ける「一括指定」です。ほかに、始まるまでの待ち時間(animation-delay)や、行って帰ってくる動きにする指定(animation-direction の alternate)もあります。跳ねる点は、alternate で「上がる→下がる」をくり返しています。

transform:回す・動かす・伸ばす

動きそのものは transform で作っています。部品を回したり、動かしたり、伸び縮みさせたりする指定です。

書き方意味使った見本
rotate(360deg)回す(360度で1周)回る輪・回る四角
translateY(-18px)上下に動かす(マイナスは上)跳ねる点・色づく文字
scaleY(0.35)縦に縮める(1が元の大きさ)伸び縮みする棒

transform で動かしても、まわりの文章や枠の位置はずれません。MDNでも、通常の文書の流れを乱さずに、形や位置を変えられる、と説明されています。ローディングを置いても、まわりのレイアウトががたつかないのはこのためです。

順番に見せる:animation-delay

点や棒が「順番に」動いて見えるのは、同じ台本を、少しずつ時間をずらして再生しているからです。ずらしているのが animation-delay(待ち時間)です。

跳ねる点は、2つ目を0.15秒、3つ目を0.3秒待たせています。伸び縮みする棒は、反対に -0.5秒〜-0.1秒と、マイナスの値にしました。MDNの説明では、マイナスにすると、アニメーションはすぐに始まり、周期の途中から再生されます。ページを開いた瞬間から、すでに波の形になっているのはこのためです。

ここまでの3つ(@keyframes・animation・transform)は、MDNでは2015年9月から主要なブラウザで使える機能とされています。いまのスマホやパソコンのブラウザなら、特別な準備なしで動きます。

数値を変えるとどうなるか

同じコードでも、数値を1つ変えるだけで印象が変わります。ここに並べた見本も、最初から動いています。

速さ:animation-duration

0.4秒
0.9秒
(見本)
2秒

速いと急かされているように、遅いと止まりかけているように見えます。回る輪なら、見本の0.9秒前後が落ち着いて見える、というのがKAKERUの判断です。

動き方:animation-timing-function

linear
(見本)
ease-in-out

linear は、最初から最後まで同じ速さです。ease-in-out は、ゆっくり始まって速くなり、最後にまたゆっくりになります。回る輪を ease-in-out にすると、1周ごとに「ため」ができて、別の表情になります。

ずらし方:animation-delay

ずらさない
0.15秒ずつ
(見本)
0.25秒ずつ

ずらさないと、3つが同時に跳ねて、1つのかたまりに見えます。順番に見えるのは、ずらしがあるからです。ずらしを大きくすると、波がゆっくり伝わるように見えます。

スマホと、見る人への配慮

ローディングは小さな部品ですが、サイトに来た人のほとんどが目にします。気をつけたいことを4つにまとめます。

「動きを減らす」設定の人には、動きを小さくする

画面の動きで気分が悪くなる人や、動きが気になって集中しにくい人がいます。そうした人は、スマホやパソコンで「動きを減らす」設定をオンにしていることがあります。iPhoneなら「設定 > アクセシビリティ > 動作 > 視差効果を減らす」、Windows 11なら「設定 > アクセシビリティ > 視覚効果 > アニメーション効果」です。

CSSの prefers-reduced-motion(プリファーズ・リデュースド・モーション)を使うと、この設定がオンの人にだけ、別の見た目を出せます。MDNでは、2020年1月から主要なブラウザで使える機能とされています。

@media (prefers-reduced-motion: reduce) {
  .kd-ld-ring { animation: kd-ld-fade 2s ease-in-out infinite; }
}

見本のコードでは、この設定の人には、回したり跳ねたりせず、明るさだけをゆっくり変える形に切り替えています。ローディングには「いま待っている」ことを伝える役目があるので、全部止めるのではなく、動きの小さい表現に置きかえました。

ふだんの見え方
「動きを減らす」がオンのとき

色は、背景との差を3:1以上に

ローディングの輪や点は、文字ではなく「図」です。ウェブのアクセシビリティの国際的な基準(WCAG)では、図と背景の色の差(コントラスト比)を 3:1以上 にする基準があります。

KAKERUのブランドカラーの青 #0EA5E9 は、白い背景に対して計算すると約2.8:1で、少し足りません。そこで見本では、同じ系統で濃い #0284C7(約4.1:1)を使いました。輪の薄い部分(#E0F2FE)は飾りなので、動いて見える濃い部分で3:1を超えるようにしています。

文字の見本は、ふだんの色を灰色の #64748B(約4.8:1)にしています。文字は4.5:1以上が基準ですが、18ポイント以上、または14ポイント以上の太字は「大きな文字」として3:1以上が基準です。見本の文字は24pxの太字なので、色づいたときの #0284C7 も基準を満たします。

トミー

ブランドカラーは、そのまま使うと薄すぎることがあります。
KAKERUなら、ロゴや帯にはブランドの青、ローディングや細い線には一段濃い青、と使い分けます。

読み上げソフトに「読み込み中」を伝える

目が見えない人や見えにくい人は、画面の文字を読み上げソフトで聞いています。くるくる回る輪だけでは、読み上げソフトには何も伝わりません。

そこで見本では、動く部分に aria-hidden="true"(読み上げの対象から外す目印)を付けて、かわりに「読み込み中」という文字を入れています。この文字は kd-ld-sr というクラスで、画面では1pxに切り取って見えなくしています。

外側の箱の role="status" は、MDNの説明では、ユーザーへの参考情報を知らせる場所の目印です。中身が変わると、読み上げソフトが、いまの操作をじゃましないタイミングで読み上げます。MDNは、対応する環境を広げるために aria-live="polite" も一緒に書くことを勧めているので、見本にも入れました。

注意したいのは、読み上げの合図になるのは「中身が変わったとき」だという点です。MDNは、先に空の箱を置いておき、あとから中身を入れる順番を勧めています。実際のサイトでは、読み込みが始まったら「読み込み中」を入れ、終わったら消します。この出し入れは、JavaScriptなどサイト側の仕組みの仕事です。CSSが受け持つのは、見た目と動きまでです。

やりすぎに注意

  • 速い点滅にしない。WCAGには「点滅は1秒間に3回まで」という基準があります。光らせる表現を作るときは、ゆっくりにします
  • 終わったら消す。WCAGには、自動で始まって5秒以上続く動きには、止めたり隠したりする手段を用意する、という基準もあります。ローディングは、読み込みが終わったら消えるのが前提です。ずっと回り続ける飾りとしては使いません
  • 1つの画面に1つ。いくつも並べると、どこを待っているのか分からなくなります
  • 一瞬で終わる場所には出さない。すぐ消えるローディングは、ちらつきに見えます

KAKERUならこう使う/使わない

最後に、作り手としての判断です。

使う場面

  • フォームの送信ボタンを押したあと。ボタンの中に小さな回る輪を出して、「押せた」「いま送っている」ことを伝えます
  • 画像の多いページやWebカタログなど、表示に時間がかかる場所。待っている場所そのものに、同じ大きさの枠ごと置きます
  • 迷ったら、回る輪。やわらかい印象のサービスなら跳ねる点。文字の見本は、何を待っているかまで書けるので「送信中」「画像を読み込み中」のように言葉を変えて使います

使わない場面

  • ページを開くたびに、全画面で出すオープニングの演出。中身が見えるまでの時間が延びるだけになるので、KAKERUなら作りません
  • 読み込みの遅さを、ごまかすため。画像が重いなど、遅い原因を直すほうが先です
トミー

ローディングは「待たせている」ことの合図です。
かっこよく見せる前に、「待ち時間を短くできないか」を先に考えたいところです。

まとめ

  • ローディングの「くるくる」は、CSSだけで作れる。JavaScriptは要らない
  • @keyframes が動きの台本、animation が再生のしかた、transform が動かし方
  • 順番に見せるのは animation-delay。マイナスにすると、開いた瞬間から途中の形で動く
  • 「動きを減らす」設定の人には、prefers-reduced-motion で動きの小さい表現に置きかえる
  • 色は背景との差を3:1以上に。読み上げソフトには「読み込み中」の文字で伝える

まずは、回る輪のコードをコピーして、秒数や色を1つずつ変えてみてください。数値と動きの関係が、手で触ると早くつかめます。

参考にした資料

いずれも2026年10月6日に確認しました。ブラウザの対応状況や、OSの設定画面の名前は変わることがあります。最新の情報は各ページでご確認ください。コントラスト比は、WCAGの計算式で計算した値です。

ふだんの制作の話や、作ったものの裏側は Instagram と X でも出しています。

関連記事

CSSfilterプロパティ10種の関数の違いを解説
「なんかダサい」を直す順番|デザイナーが最初に見る5つ
CSSだけで作るローディングアニメーション コピペで使える5種類と、見る人への配慮

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA