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

CSS プログレスバー 円形ゲージ9選 — 数値を変えるだけ

css プログレスバー 円で探している人が見たいのは、直線の帯ではなく丸いリングやゲージで割合を示すCSS部品です。今回は実際に動く9種類を用意し、どれもwidthではなくtransformとconic-gradientだけで値を表現しています。

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

9つの css プログレスバー デザイン は人気順ではなく、値の扱い方が難しくなる順に並べました。帯が1本だけ伸び縮みする2つ(01・02)から始まり、形をリングと半円に変えた2つ(03・04)、値が段階しかない・そもそも分からないという2つ(05・06)を経て、数字やラベル、複数ステップと組み合わせた3つ(07〜09)で終わります。コードは要点だけを載せ、完全なファイル一式はzipにあります。まだ数値が届かず06の不定バーのように回しておくだけならCSS ローディング スピナーのほうが素直で、返答を待つ会話画面ならAIチャットのローディングアニメーションがその役を引き受けます。

01基本の線形の塗り

プログレスバー css アニメーション の基本

塗りつぶしバーが --percent カスタムプロパティの値だけ scaleX で伸び、スクロールではなくアップロードなど実際の進捗数値をそのまま反映します。

どこで使うか

ファイルアップロードの進捗表示やフォーム送信の進行状況に向いています。

基本の線形の塗り
新しいタブで開く

01 · 基本の線形の塗り — 計測 累積面積 2.051% · 動いたフレーム 15/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

scaleX@property2초 루프
@property --percent {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
.track { --percent: 0; position: relative; overflow: hidden; }
.bar {
  position: absolute; inset: 0;
  transform: scaleX(calc(var(--percent) / 100));
  transform-origin: left center;
}
.track.is-demo { animation: fill $duration $easing infinite; }
@keyframes fill {
  0%   { --percent: 0; }
  60%  { --percent: 76; }
  100% { --percent: 76; }
}

02ストライプアニメーション

どう動くか

斜めの縞模様の背景が background-position で絶えず流れ、値が変わらない区間でも何かが進行中だという印象を与えます。

どこで使うか

大量データ処理の表示やバックグラウンド同期のバーに向いています。

ストライプアニメーション
新しいタブで開く

02 · ストライプアニメーション — 計測 累積面積 1.883% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

background-positionrepeating-linear-gradient1초 루프
.bar {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(45deg, $color 0 10px, rgba($color, .55) 10px 20px);
  background-size: 28px 28px;
}
.bar.is-demo { animation: stripe-move $duration $easing infinite; }
@keyframes stripe-move {
  from { background-position: 0 0; }
  to   { background-position: 28px 0; }
}

03conic-gradientリング

どう動くか

ドーナツ型のリングが --percent の値まで満たされますが、数字は一切表示しません。値が低・中・高の3ゾーンを通過するたびに conic-gradient の色そのものが変わり、青(低)から黄色(中)を経て、最も高い区間では赤ではなく濃いインク色になります。

どこで使うか

サーバーのリソース使用率やバッテリー・ストレージの残量表示に向いています。

conic-gradientリング
新しいタブで開く

03 · conic-gradientリング — 計測 累積面積 3.458% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

conic-gradient색 구간 전환@property
@property --percent {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
.ring {
  --percent: 0; --zone: #{$color};
  background: conic-gradient(var(--zone) calc(var(--percent) * 1%), rgba(255, 255, 255, .35) 0);
}
.ring.is-demo { animation: sweep $duration $easing infinite, zone $duration steps(1) infinite; }
@keyframes zone {
  40%  { --zone: #{$color}; }
  41%  { --zone: #{$stage-yellow}; }
  75%  { --zone: #{$subject-ink}; }
}

04半円ゲージ

どう動くか

半円の目盛り盤の上で、針が --percent の値に合わせて rotate で回ります。スピードメーターのように片方の端からもう片方の端へだけ動き、一周はしません。

どこで使うか

速度やスコアのゲージ、目標達成度のダッシュボードに向いています。

半円ゲージ
新しいタブで開く

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

transform: rotate()반원 clip바늘
@property --percent {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
.gauge { --percent: 0; overflow: hidden; }
.gauge::before {
  width: 100%; height: 200%; border-radius: 50%;
  background: conic-gradient(from -90deg, $color calc(var(--percent) * 1.8deg), rgba($subject-ink, .12) 0);
}
.gauge__needle {
  transform-origin: bottom center;
  transform: translateX(-50%) rotate(calc(var(--percent) * 1.8deg - 90deg));
}

05セグメントステップ

どう動くか

バーは1本の帯ではなく5つの区切りに分かれ、値が上がるたびに区切りが順番にひとつずつ点灯します。

どこで使うか

電波強度の表示や、体力ゲージのようなゲームUIに向いています。

セグメントステップ
新しいタブで開く

05 · セグメントステップ — 計測 累積面積 2.794% · 動いたフレーム 20/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

opacity 단계 전환animation-delay조각 5개
.seg {
  width: 16px; height: 46px; border-radius: 4px;
  opacity: .35; transform: scaleY(.7); transform-origin: bottom;
}
.segs.is-demo .seg { animation: light 2s $easing infinite; }
.segs.is-demo .seg:nth-child(2) { animation-delay: 160ms; }
@keyframes light {
  0%, 60%, 100% { opacity: .35; transform: scaleY(.7); }
  20%, 45%      { opacity: 1;   transform: scaleY(1); background: $color; }
}

06不定バー

どう動くか

1本の短いバーが左右に往復する代わりに、長さの異なる2本の帯が時間差を付けて重なりながら通過します。

どこで使うか

マテリアルデザインのローディングバーに近い転がる印象を作り、所要時間が分からない初期読み込みや検索結果の待機に向いています。

不定バー
新しいタブで開く

06 · 不定バー — 計測 累積面積 1.542% · 動いたフレーム 19/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

두 세그먼트animation-delay 차등cubic-bezier
.seg {
  position: absolute; inset: 0;
  background: $color; transform-origin: left center;
}
.seg--a.is-demo { animation: seg-a $duration $easing infinite; }
.seg--b.is-demo { animation: seg-b $duration $easing infinite; animation-delay: $duration * .35; }
@keyframes seg-a {
  0%   { transform: translateX(-100%) scaleX(.15); }
  55%  { transform: translateX(30%)   scaleX(.7); }
  100% { transform: translateX(120%)  scaleX(.15); }
}

07パーセントラベル連動

どう動くか

リングではなく横バーの上で、塗りの先端を追いかけるように吹き出しラベルが translateX で一緒に動き、今の値を数字で示します。

どこで使うか

アンケートやオンボーディングの進行表示、スライダー型入力のプレビューに向いています。

パーセントラベル連動
新しいタブで開く

07 · パーセントラベル連動 — 計測 累積面積 7.601% · 動いたフレーム 14/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

translateX 동기말풍선CSS 변수
@property --percent {
  syntax: "<integer>";
  inherits: true;
  initial-value: 0;
}
.track { --percent: 0; container-type: inline-size; }
.bar { transform: scaleX(calc(var(--percent) / 100)); transform-origin: left center; }
.bubble {
  position: absolute; top: -30px; left: 0;
  transform: translateX(calc(var(--percent) * 1cqw - 50%));
}
.bubble__num { counter-reset: p var(--percent); &::before { content: counter(p) "%"; } }

08ステッパー進捗

どう動くか

番号付きの丸3つが線でつながり、完了した段階ごとに丸が塗りつぶされて、その間の連結線が scaleX で伸びます。

どこで使うか

前の段階が終わるまで次の丸は動き始めないため、会員登録の複数ステップフォームやチェックアウトの段階表示に向いています。

ステッパー進捗
新しいタブで開く

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

scaleX 연결선원 채움단계 3개
.stepper.is-demo .step__dot { animation: dot-fill $duration $easing both; }
.stepper.is-demo .line { animation: line-grow $duration linear both; }
.stepper.is-demo > :nth-child(2) { animation-delay: 400ms; }
.stepper.is-demo > :nth-child(3) .step__dot { animation-delay: 800ms; }
@keyframes dot-fill {
  from { background: rgba(255, 255, 255, .14); transform: scale(.85); }
  to   { background: $color; transform: scale(1); }
}
@keyframes line-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

09バッテリー型ゲージ

どう動くか

バッテリー型の枠の中の塗りが scaleX で満ち、残量が少なくなるほど色がクリーム色から黄色、警告用の赤茶色へと変わります。

どこで使うか

残量が少ないときだけ枠がわずかに点滅し、機器のバッテリー表示やリソース枯渇の警告ウィジェットに向いています。

バッテリー型ゲージ
新しいタブで開く

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

scaleX색 임계값 전환테두리 펄스
@property --percent {
  syntax: "<number>";
  inherits: false;
  initial-value: 100;
}
.battery__fill {
  --percent: 100;
  transform: scaleX(calc(var(--percent) / 100));
  animation: drain $duration $easing infinite;
}
@keyframes drain {
  0%   { --percent: 100; background: #{$color}; }
  55%  { --percent: 35;  background: #{$stage-yellow}; }
  100% { --percent: 8;   background: #{$error}; }
}

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

9つを組んでいて実際に踏んだ落とし穴は2種類です。

幅0では scaleX も効かない

1つ目は06の不定バーです。重なって流れる2本の帯をposition: absoluteで浮かせただけでは、leftやrightを指定しない絶対配置要素は中身の大きさのぶんしか幅を持たず、空の<span>は幅0のままscaleXをいくら掛けても画面に何も現れません。inset: 0で先に幅を親いっぱいに広げ、そこからtransformだけで押し出して縮めるようにしてから帯が見え始めました。この幅0の罠は帯状の部品なら形を問わず同じで、CSS タブ 切り替え アニメーションの下線バーでも最初に疑う場所になります。

inherits の使い分け

2つ目は@propertyのinheritsです。03と09は--percentを持つ要素自身が背景やリングを描くだけなのでinherits: falseで構いませんが、04の針や07の吹き出し・counter()は親の.gaugeや.trackが動かす値を子要素が読み取る構造のため、inherits: trueにしないとMDNの@property文書が示すとおり子は初期値のまま止まります。9ファイルとも構造に合わせてinheritsを使い分けてあり、開くための圧縮パスワードはbetrch52です。

アクセシビリティ

何を伝えているか

01〜05・07・09の7つはrole="progressbar"にaria-valuenowを添えて今の値を伝えますが、値が定まらない06の不定バーだけはaria-valuenowもaria-valuemin・aria-valuemaxも持ちません。08のステッパーだけは進捗バーではなくrole="list"とrole="listitem"の並びで、番号付きの丸とラベルで段階そのものを伝えます。

<div class="track is-demo" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="76" aria-label="アップロード中">
  <div class="bar"></div>
</div>

動きを減らす設定では

prefers-reduced-motion: reduceでは、03の色分けリングと09のバッテリーはそのとき止まる値に応じた色のまま固定されます。05のセグメントは動きを止めると逆にすべての区切りが点灯した状態になり、08のステッパーも全ての丸と線が完了済みの見た目に切り替わります。06の不定バーだけは値を持たないため、幅40%ほどの帯が半透明のまま静止するだけです。

CSSアニメーションの他の記事はカテゴリー一覧に、このサイトの成り立ちは紹介ページにまとめています。

FAQ

@propertyを使わずにこのゲージを作れますか?

はい、可能ですが値が切り替わる瞬間に段階を飛ばして一気に変わります。@propertyで数値として登録すると、ブラウザが毎フレームの中間値を自動で計算し、滑らかに塗りが伸びます。登録なしで同じ滑らかさを出すにはrequestAnimationFrameで自前に値を書き換えるJavaScriptが必要です。MDNの@property対応表によるとChrome・Edgeは85以降、Safariは16.4以降、Firefoxは128以降で使え、caniuseの対応表でも同じ数値を確認できます。

css ゲージ デザイン は半円と円形どちらを選べばいいですか?

値の範囲がひとつの指標を示すだけなら半円のほうが読み取りやすく、使用率やバッテリーのように低い・警告といった状態を色でも区別したい場合は円形のほうが省スペースです。同じ画面に両方の形を混ぜると、どちらが何を示しているのか伝わりにくくなるので避けたほうが無難です。03のリング形だけをもっと使いたい場合は、数値そのものも数え上がる円形のスタットリング ウィジェットが続きになります。

値をサーバーから受け取ってリアルタイムに変えるには?

React版のようにpercentをpropsや状態として受け取り、インラインスタイルの--percentの値だけを書き換えれば十分です。@propertyで登録済みのカスタムプロパティは値が変わるたびにtransitionを掛けておくだけで新しい値まで自動的に補間されるので、独自のアニメーションループを組む必要はありません。

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

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