GODRICH
#cssアニメーション#ボタン#ローディング#トランジション#スクロール#ダッシュボード#実用ui#デザイントレンド

【コピペOK】プログレスバー css アニメーション 9選

プログレスバー css アニメーションは、スクロールした量だけを手がかりに「今どこまで読んだか」を見せるCSSの部品です。CSSだけ・JS不要で、上部バー・円形バッジ・点ナビ・縦バー・文字塗り・数値・章ステップ・目次・残り時間の9種類を集めました。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

9つは「スクロール ダウン アニメーション css」のような誘導の矢印ではなく読んだ量そのものを見せる部品で、人気順ではなく読者が意識せずに視界へ入る場所から並べました。画面の端でいつも見えるもの(01〜04)の次に、本文の中で直接目に入るもの(05〜06)、最後に記事の構造そのものを説明するもの(07〜09)です。01・02・04・05・06・09の6つはanimation-timeline: scroll()ひとつだけでスクリプトなしに動き、03・07・08の3つはスクロール位置に応じてJSがクラスを切り替える方式です。scroll()をまだ使えないブラウザ向けの代替版は落とし穴の章にまとめてあります。進み具合ではなく要素を順番に出したい場合は順次表示アニメーションを先に見るほうが早く、横方向の進行はCSSカルーセルが引き受けます。

01上部の細いバー

scroll(root)ひとつで動く

画面最上部に張り付いた3pxのバーが、読んだ分だけ左から満ちていきます。実装はanimation-timeline: scroll(root)ひとつで、JavaScriptは使いません。長い記事のヘッダー直下や、チュートリアル文書の冒頭に向いています。

上部の細いバー
新しいタブで開く

01 · 上部の細いバー — 計測 累積面積 1.0% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

scroll()3px왼쪽 정렬

長い記事のヘッダー直下に

.bar {
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;

  @supports (animation-timeline: scroll()) {
    animation: fill linear both;
    animation-timeline: scroll(root);
  }
}
@keyframes fill { to { transform: scaleX(1); } }

02円形リングバッジ

「css プログレスバー 円」をconic-gradientで

画面右下に浮かぶ円形バッジが、conic-gradientのリングで読んだ分だけ満ちていきます。@property --pを数値として登録しているので、リングの角度がなめらかに補間されます。フローティングのトップへ戻るボタンと組み合わせると、ひとつのボタンで移動と進捗表示を兼ねられます。

円形リングバッジ
新しいタブで開く

02 · 円形リングバッジ — 計測 累積面積 0.736% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

conic-gradient@property고정 위치

トップへ戻るボタンと兼ねる

@property --p { syntax: '<number>'; initial-value: 0; inherits: false; }

.badge {
  --p: 0;
  border-radius: 50%;
  background: conic-gradient($color calc(var(--p) * 1%), $stage-paper 0);

  @supports (animation-timeline: scroll()) {
    animation: fill-ring linear both;
    animation-timeline: scroll(root);
  }
}
@keyframes fill-ring { from { --p: 0; } to { --p: 100; } }

03セクションドットナビ

IntersectionObserverで判定する

縦に並んだ6つの点のうち、今読んでいるセクションの点だけが拡大して明るくなります。実装ではIntersectionObserverが画面に入ったセクションを判定し、対応する点に.is-activeを付けます。ワンページ構成のストーリーサイトや、ランディングページのセクションナビに向いています。

セクションドットナビ
新しいタブで開く

03 · セクションドットナビ — 計測 累積面積 0.683% · 動いたフレーム 21/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

scale 1.6배점 6개세로 정렬

ワンページ構成のナビに

const io = new IntersectionObserver((entries) => {
  const top = entries
    .filter((e) => e.isIntersecting)
    .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
  if (top) setActive(sections.indexOf(top.target));
}, { threshold: [0.3, 0.6] });
sections.forEach((el) => io.observe(el));

04サイド縦バー

同じ仕組みを縦方向に

画面右端の細いトラックが、上から下へ向かって読んだ位置ぶんだけ満ちていきます。01の上部バーと同じscroll(root)の仕組みを、縦方向に使っただけです。ドキュメントサイトや、長い技術記事の右余白に向いています。

サイド縦バー
新しいタブで開く

04 · サイド縦バー — 計測 累積面積 0.833% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

scaleY우측 4px고정

ドキュメントサイトの右余白に

.rail__fill {
  height: 100%;
  transform: scaleY(0);
  transform-origin: top;

  @supports (animation-timeline: scroll()) {
    animation: fill-y linear both;
    animation-timeline: scroll(root);
  }
}
@keyframes fill-y { to { transform: scaleY(1); } }

05文字塗りつぶし

background-clipで切り抜く

見出しの文字色が、読んだ割合だけ左から塗り替わっていきます。background-clip: textで切り抜いたグラデーションを@property --pのパーセンテージで動かしているだけで、画像は一枚も使いません。ヒーローの見出しや、記事タイトルを強調したい場面に向いています。

文字塗りつぶし
新しいタブで開く

05 · 文字塗りつぶし — 計測 累積面積 2.938% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

background-clip:textlinear-gradient두 색

ヒーローの見出しに

@property --p { syntax: '<percentage>'; initial-value: 0%; inherits: false; }

.headline {
  --p: 0%;
  background-image: linear-gradient(90deg, $color var(--p), $dim var(--p));
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

06数値パーセント

整数として登録する理由

右上の小さな数字が、スクロールした分だけ0から100まで整数で上がっていきます。@property --numを整数として登録しているので、小数点を挟まずに数字がひとつずつ切り替わります。長いアンケートやチュートリアルの進捗表示に向いています。

数値パーセント
新しいタブで開く

06 · 数値パーセント — 計測 累積面積 0.872% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

@property정수 보간% 붙이기

長いアンケートの進捗に

@property --num { syntax: '<integer>'; initial-value: 0; inherits: false; }

.counter__num {
  --num: 0;
  counter-reset: num var(--num);
  &::before { content: counter(num) '%'; }

  @supports (animation-timeline: scroll()) {
    animation: count-up linear both;
    animation-timeline: scroll(root);
  }
}
@keyframes count-up { from { --num: 0; } to { --num: 100; } }

07章ステップ

scale(1.25)を挟んだ理由

上に並んだ4つの章番号のうち、今読んでいる章の丸だけが色で塗りつぶされます。色を瞬時に切り替えるだけでは変化する一瞬が短すぎて測定に引っかからなかったため、scale(1.25)のポップを挟んで変化区間を広げてあります。チュートリアルシリーズや、複数ステップのガイド記事に向いています。

章ステップ
新しいタブで開く

07 · 章ステップ — 計測 累積面積 3.558% · 動いたフレーム 16/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

원 채움챕터 4개scale 1.25배

複数ステップのガイドに

@keyframes fill-2 {
  0%, 25%    { background: transparent; transform: scale(1); }
  33%        { background: $color; transform: scale(1.25); }
  40%, 100%  { background: $color; transform: scale(1); }
}
.step:nth-child(2) .step__circle { animation: fill-2 linear both; }

08目次ハイライト

ピルがスライドして追従する

サイドの目次で、今読んでいる見出しにだけ背景のピルがスライドして追従します。濃い単色のピルは2行にまたがる遷移の途中で文字とのコントラストが崩れたため、14%の薄いティントと左のボーダーに変えてあります。ドキュメントサイトの目次や、長いガイド記事のスクロールスパイに向いています。

目次ハイライト
新しいタブで開く

08 · 目次ハイライト — 計測 累積面積 21.896% · 動いたフレーム 15/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

translateY 알약현재 항목만좌측 보더 3px

ドキュメントサイトの目次に

.toc__pill {
  position: absolute;
  background: rgba(47, 109, 246, .14);
  border-left: 3px solid $color;
  animation: move $dur-loop ease-in-out infinite;
}
@keyframes move {
  0%, 10%  { transform: translateY(0); }
  25%, 35% { transform: translateY($row); }
  100%     { transform: translateY(0); }
}

09残り読了時間

残り分数を差し引いて数える

「残りN分」の数字が、スクロールするほど減っていきます。残り分数は全体の分数から読んだ割合を差し引いた値で、@property --minを整数として登録して滑らかに数えています。長い記事のヘッダーや、ニュースレターのWeb版に向いています。

残り読了時間
新しいタブで開く

09 · 残り読了時間 — 計測 累積面積 1.545% · 動いたフレーム 12/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

카운트다운분 단위scroll() 연동

ニュースレターのWeb版に

@property --min { syntax: '<integer>'; initial-value: 12; inherits: false; }

.time__num {
  --min: 12;
  counter-reset: min var(--min);
  &::before { content: counter(min); }
}
@keyframes count-down { from { --min: 12; } to { --min: 0; } }

どこで崩れるか — 落とし穴

対応の足並みが揃っていない

01・02・04・05・06・09の6つはanimation-timeline: scroll()ひとつだけでJavaScriptなしに動きますが、この機能への対応はまだ足並みが揃っていません。実測(2026-09-10)は下の表の通りです。

機能 Chrome・Edge Safari Firefox
animation-timeline scroll() 115以降 26以降(2025年9月) 158以降、2026年9月時点の安定版はフラグの内側
@property 85以降 16.4以降 128以降

steps(1)だけでは動きと見なされない

読み終わりを祝いに変える紙吹雪アニメーションも同じ落とし穴を抱えており、進捗が100%へ届く瞬間を取り違えると何もない画面で弾けてしまいます。

対応バージョンの一覧はMDNのanimation-timeline対応表とMDNの@property対応表で確認できます。実際にコードを動かして計測しているときに踏んだ落とし穴もひとつあります。07の章ステップを色の瞬間切り替え(steps(1))だけで作ると、フレームごとに変化がある区間がわずか4枚しかなく、測定スクリプトに「ほとんど動いていない」と判定されました。切り替わる瞬間にscale(1.25)のポップを挟んで変化区間を広げたところ、16枚まで増えてようやく動きとして認識されました。scroll()にまだ対応していないブラウザでは、scroll()に頼る6つの進行表示が止まったままになるため、zipのreact/版は9つ全部についてwindowのscrollイベントやJSでの区間判定(03・08のようなIntersectionObserverなど)で同じ値を計算し直す代替コードを最初から積んであります。この値を反映済みの9ファイルを開く圧縮パスワードは3rmg234aで、下からzipひとつにまとめて受け取れます。

アクセシビリティ

止めたあとどの状態で残すか

9つともprefers-reduced-motion: reduceではアニメーションを止めます。01・02・04・05・06・07・09のように進捗を累積で満たしていくものは、進捗0の初期状態ではなく読み終えた最終状態で固定されます。一方、03の点ナビと08の目次のように今見ている区間だけを点灯させるものは、最初の項目が点灯した状態で固定されます。06の数値と09の残り時間のようにcounter()で描いた数字はスクリーンリーダーがそもそも読み上げられないため、数字自体はaria-hiddenで隠し、包む要素にrole="status"またはrole="progressbar"とaria-valuenowを別に付けています。08の目次で今読んでいる見出しを指す項目は実際の<a href="#見出しid">なので、キーボードだけでもそのままたどり着けます。03の点ナビの点は装飾のためaria-hiddenで隠されており、スクリーンリーダーやキーボード移動の対象にはなりません。

@media (prefers-reduced-motion: reduce) {
  .bar, .rail__fill, .badge,
  .headline, .counter__num, .time__num { animation: none !important; }
  .bar, .rail__fill { transform: scaleX(1); }
}

次に読む

prefers-reduced-motion自体の対応状況はMDNの該当ページで確認できます。ほかのCSSアニメーションを探すならカテゴリー一覧、このサイトが何を配っているかは紹介ページで説明しています。

FAQ

scroll()にまだ対応していないブラウザではどうなりますか?

animation-timeline: scroll()を使う6つ(01・02・04・05・06・09)は@supports (animation-timeline: scroll())で囲んであるため、対応がなければ中のアニメーションはただ適用されません。残り3つ(03・07・08)はもともとJSでスクロール位置を判定する方式です。zipのreact/版は9つ全部についてJSで同じ値を計算し直しているので、CSSの代わりにこちらのコンポーネントを使えばFirefoxを含むすべてのブラウザで進捗が動きます。

「css プログレスバー デザイン」を9つのうちいくつ同時に置いても大丈夫ですか?

01の上部バーと04の縦バーのように置き場所が重ならない組み合わせなら問題ありません。ただし06の数値と09の残り時間のように、同じ進捗を別の数字で見せるものは、どちらか一方だけにしてください。両方点けると、どちらの数字を見ればいいのか分かりにくくなります。

見出しが少ない記事でも08の目次ハイライトは使えますか?

H2が4つに満たないと、ピルの移動がほとんど起きず効果そのものが見えません。当サイトではH2が4つ以上ある記事にだけ08を付け、それより短い記事には01の上部バーだけを残す運用にしています。バーではなく点や目次で現在地を示す派生はスクロールインジケーター9選に別途まとめました。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。