1. はじめに
「0 から 1000 まで数字が増えていく表示」を見たことがあると思います。
たとえば、以下のようなUIです。
- スコアが加算される表示
- 売上やPVの集計表示
- 経験値や報酬の獲得演出
- ダッシュボードの数値アニメーション
こうした 数値が変化するUI は、ただ値を一気に切り替えるよりも、少しアニメーションさせた方が変化を認識しやすくなります。
今回は、JavaScriptで 数値カウントアップUI(Number Animation) を作る方法を整理します。
requestAnimationFrame を使った基本実装を中心に、duration・easing・表示更新の考え方まで、できるだけシンプルに見ていきます。
2. 数値アニメーションは何のために使うのか
数値カウントアップUIの目的は、単に見た目を派手にすることではありません。
大事なのは、「変化が起きた」ことをユーザーに伝えること です。
たとえば、1000 という数字が急に 1280 に切り替わると、増えたこと自体は分かっても、
- どのくらい増えたのか
- 今まさに加算されたのか
- 演出的に強調したい変化なのか
が伝わりにくいことがあります。
一方、数値が少しずつ増えていくと、
- 増加した事実が視覚的に分かりやすい
- 「成果が積み上がった」感覚を出しやすい
- UI全体に手触りが出る
というメリットがあります。
つまり、数値アニメーションは 装飾 というより フィードバック設計 の一部です。
3. 実装の考え方は意外とシンプル
基本の考え方は次の3つです。
- 開始値と終了値を決める
- 何ミリ秒で終えるかを決める
- 進捗に応じて表示する数値を計算する
たとえば、
- start = 0
- end = 1000
- duration = 1200ms
なら、0ms時点では 0、600ms時点では途中の値、1200ms時点では 1000 を表示します。
この「途中の値」を毎フレーム更新するために、requestAnimationFrame を使います。
4. まずは最小構成で考える
数値アニメーションの基本は、進捗率 t を 0〜1 で求めることです。
t = 経過時間 / durationただし、duration を超えた後は 1 を超えないようにします。
t = Math.min(elapsed / duration, 1)そして、開始値と終了値の間を補間します。
value = start + (end - start) * tこれで、時間に応じて数値がなめらかに変化します。
たとえば start が 0、end が 1000 なら、
- t = 0 → 0
- t = 0.5 → 500
- t = 1 → 1000
になります。
この考え方は、以前の Interpolation の記事ともつながっています。
数値カウントアップも本質的には 値の補間 です。
5. requestAnimationFrame を使った基本実装
まずは最小のサンプルです。
const output = document.getElementById('count');
function animateCount(start, end, duration) {
const startTime = performance.now();
function update(now) {
const elapsed = now - startTime;
const t = Math.min(elapsed / duration, 1);
const value = start + (end - start) * t;
output.textContent = Math.floor(value);
if (t < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}
animateCount(0, 1000, 1200);このコードでは、0 から 1000 までを 1200ms かけて増やしています。
ポイントは以下です。
performance.now()で開始時刻を取る- 毎フレーム
elapsedを計算する tを 0〜1 に収める- 補間した値を表示する
- 終わっていなければ次フレームを予約する
かなりシンプルですが、これで数値アニメーションの土台はできています。
6. なぜ setInterval より requestAnimationFrame がよいのか
数値更新だけなら setInterval でも動きます。
ただ、UIアニメーションとして考えるなら requestAnimationFrame の方が扱いやすいです。
理由は、ブラウザの描画タイミングに合わせて実行されるからです。
つまり、
- 画面更新と揃えやすい
- 無駄な更新が減りやすい
- 他のアニメーションと合わせやすい
という利点があります。
Idle Interface のこれまでの記事でも何度か扱ってきましたが、UIアニメーションを設計するなら、まず requestAnimationFrame ベースで考えるのが自然です。
7. Math.floor だけでよいのか
最小実装では Math.floor(value) を使いました。
これで整数表示としては十分です。
ただし、用途によって表示方法は変わります。
たとえば、
- 小数第1位まで見せたい
- 3桁区切りにしたい
- 通貨表示したい
- 最後だけピタッと終了値に合わせたい
といったケースがあります。
たとえば 3桁区切りなら、次のようにできます。
output.textContent = Math.floor(value).toLocaleString();12000 なら 12,000 のように表示されるので、ダッシュボードや集計表示ではかなり見やすくなります。
8. easing を入れると「それっぽさ」が増す
ここまでの補間は等速です。
つまり、最初から最後まで同じペースで増えます。
でも実際のUIでは、
- 最初は速く
- 最後はゆっくり止まる
ような動きの方が気持ちよく見えることが多いです。
そこで使うのが easing です。
たとえば easeOutCubic は次のように書けます。
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}そして、補間に使う t をそのまま使う代わりに、easing を通した値に置き換えます。
const eased = easeOutCubic(t);
const value = start + (end - start) * eased;こうすると、序盤は勢いよく増えて、終盤はゆっくり収束する動きになります。
数値アニメーションでは、この「終わり方」がかなり大事です。
最後に少し減速するだけで、UIの印象がかなりよくなります。
9. 実用では「再利用しやすい形」にしておく
実案件や複数箇所で使うことを考えるなら、関数として切り出しておくと便利です。
function animateNumber({
element,
start = 0,
end = 100,
duration = 1000,
easing = t => t,
format = v => Math.floor(v).toString()
}) {
const startTime = performance.now();
function update(now) {
const elapsed = now - startTime;
const t = Math.min(elapsed / duration, 1);
const eased = easing(t);
const value = start + (end - start) * eased;
element.textContent = format(value);
if (t < 1) {
requestAnimationFrame(update);
}
}
requestAnimationFrame(update);
}使う側はこんな形です。
animateNumber({
element: document.getElementById('count'),
start: 0,
end: 12000,
duration: 1400,
easing: easeOutCubic,
format: v => Math.floor(v).toLocaleString()
});この形にしておくと、
- duration を変える
- easing を差し替える
- 表示形式を変える
といった調整がしやすくなります。
10. 数値アニメーションでよくある注意点
10-1. 終了値にぴったり合わない
途中計算の都合で、最後に 999 のまま終わるような実装にしてしまうことがあります。
これを避けるため、終了時には最終値を明示的に入れておくと安心です。
if (t >= 1) {
element.textContent = format(end);
return;
}10-2. 短すぎると読めない
たとえば 0 → 100000 を 300ms で動かすと、変化が速すぎて認識しづらくなります。
逆に長すぎても待たされる感じが出ます。
まずは 800ms〜1500ms くらいから試すと調整しやすいです。
10-3. 何度も連打すると重複しやすい
ボタンを押すたびに新しいアニメーションを始める場合、前のアニメーションと重なって意図しない表示になることがあります。
実運用では「前のアニメーションを止める」「現在値から再開する」といった制御も考えた方がよいです。
10-4. 数字だけ動かしても伝わらないことがある
数値だけでは変化が弱い場合、
- 色の変化
- スケールの変化
- アイコンやラベルの補助
- 差分表示(+120 など)
を組み合わせると、より伝わりやすくなります。
11. どんな場面で使うと効果的か
数値アニメーションは、次のような場面で特に相性がよいです。
- 売上やPVなどの集計表示
- ゲームのスコア加算
- 経験値やコイン獲得
- プログレスバー横の数値
- ダッシュボードのKPI表示
- レベルアップや報酬獲得の演出
逆に、常に高速で更新される値に毎回大きなアニメーションを付けると、かえって読みにくくなることもあります。
大事なのは、「変化を見せたい場面」に絞って使うことです。
12. 今回のポイント
今回の数値カウントアップUIは、見た目こそシンプルですが、アニメーション設計の基礎が詰まっています。
- requestAnimationFrame で毎フレーム更新する
- 経過時間から進捗率を作る
- 開始値と終了値を補間する
- easing で気持ちよい終わり方を作る
- format で表示を整える
つまり、数値アニメーションは単体の小技というより、UI変化をどう見せるかの基本練習 としてかなり良い題材です。
これまで扱ってきた deltaTime、easing、Interpolation の考え方も、こうした実用UIに落とし込むとぐっと身近になります。
13. 実験:Number Animation Playground: Linear vs Ease-Out
以下の実験では、数値カウントアップUIの動きを実際に確認できます。
開始値・終了値・duration を変えながら、linear と ease-out の違いを見比べてみてください。
数値アニメーションは一見シンプルですが、どの速さで増えるか、どのように止まるか によって印象がかなり変わります。
特に ease-out は終盤で少し減速するため、ただ数値が変わるだけでなく「自然に収まる」感じを作りやすいのが特徴です。
観察ポイント
linearは一定速度で増えるease-outは最初が速く、最後がゆっくり止まる- duration が短すぎると変化を認識しづらい
- duration が長すぎると反応が鈍く見える
- 数値だけでなく、進捗バーも合わせると変化がより伝わりやすい
今回のデモでは、数値アニメーションを単体で見ています。
実際のUIでは、これに色変化・スケール変化・アイコン・ラベルなどを組み合わせることで、より分かりやすいフィードバックにできます。
14. まとめ
JavaScriptで数値カウントアップUIを作るときは、まずは難しく考えすぎず、
- 開始値
- 終了値
- duration
- 補間
- easing
の5つに分けて考えると整理しやすくなります。
数値アニメーションは、派手な演出というより、ユーザーに変化を伝えるためのUIです。
だからこそ、速さや止まり方、表示形式を丁寧に整えると、全体の印象もかなり良くなります。
次に progress bar や reward popup のようなUIを作るときにも、この考え方はそのまま応用できます。
小さなUIパーツですが、アニメーション設計の練習題材としてはとても優秀です。

コメントを残す