本文へスキップ

数字カウントアップ

画面に入ると数字が0から目標値へ駆け上がる。実績や統計の見せ場に。

プレビュー

スクロール

操作枠内をスクロールすると動きます。

仕様書

向く場面
  • 導入社数・DL 数など大きさが説得材料の実績
  • 統計セクションの見せ場
  • 3〜4 個までの数字の並び
避ける場面
  • 価格・残高・在庫など正確な値を即読ませる数字
  • 頻繁に更新されるダッシュボードの値
構成要素
  • 数値
  • キャプション
  • スクロール余白
持っている状態
  • 通常
キーボード

スクロール(キーボードは ↑↓/PageDown で可)。数値は操作不可

支援技術

動く数値は aria-hidden、最終値は sr-only で「1,280 ダウンロード数」と塊で読ませる。HTML 初期値は最終値で JS が 0 に戻す。reduced-motion では最初から最終値

動き

0→1,280 を 1,400ms、cubic ease-out(1−(1−t)³)で着地感。可視率 50% で一度だけ再生

目的見せる

デザインの要点

  • 経過時間÷1,400ms を進捗にして値を出す。setInterval で一定量ずつ足すと端末や負荷で所要時間が変わり、最終値も丸めでずれる
  • イージングは 1−(1−t)³。終盤を緩めると目標値に「着地」する。線形だと最後まで同じ速さで止まった瞬間が唐突
  • HTML には最終値 1,280 を書き、JS が動いたときだけ 0 に戻す。JS 無効・失敗で「0」が残ると誤情報になる
  • tabular-nums で桁幅を固定する。カンマの増減で幅が揺れると、数字より枠の揺れに目が行く

使いどころ

実績や統計を「数字そのものが主役」として見せたいときに向く。導入企業数、累計ダウンロード数、削減できた時間のように、大きさ自体が説得材料になる数値と相性がよい。0から目標値へ駆け上がる動きは視線を引きつけ、その数字を読ませたいという意図をはっきり伝えられる。一方で、価格やユーザーの残高、在庫数のように「正確な値をすぐ知りたい」数字をカウントアップさせるのは避けたい。確定するまで読めないうえ、途中の値が一瞬でも本当の値のように見えてしまう。ダッシュボードで頻繁に更新される数値も、動くたびに注意が奪われるため静的に出す方が使いやすい。同じ画面に並べる数字は3〜4個までにし、それぞれ少しずつ開始をずらすと順に読ませられる。

仕組み

IntersectionObserver で要素が画面に入ったことを検知し、そこからアニメーションを始める。スクロールイベントで位置を計算する必要はなく、observer に任せる方が軽く、実装も短い。1回だけ動かせばよいので、発火したら unobserve するのを忘れないようにする。数値の更新は requestAnimationFrame のループで、経過時間を持続時間で割った進捗(0〜1)から現在値を求める形にする。進捗にイージング(終盤を緩める ease-out 系)をかけると、目標値に「着地する」感触が出て、ただの線形増加より気持ちよくなる。表示は toLocaleString() で桁区切りを付け、小数を含む場合は toFixed() で桁数を固定して揺れないようにする。持続時間は1.5〜2秒程度が目安で、長すぎると読みたい人を待たせる。

実装の注意

桁区切りが入る数値では、カンマが増減するたびに文字幅が変わってレイアウトが揺れる。font-variant-numeric: tabular-nums を指定して数字の字幅を揃え、さらに最終値の幅を min-width で確保しておくと安定する。setInterval で一定量ずつ足す実装も見かけるが、端末の性能やタブの状態で所要時間が変わるうえ、刻み幅の丸めで最終値がぴったりにならないことがある。requestAnimationFrame と経過時間から計算すれば、どの端末でも同じ時間で同じ値に着地する。画面に入る前の初期表示を0にしておくと、JavaScriptが無効・失敗した環境で「0」が残って誤情報になる。HTMLには最終値を書いておき、スクリプトが動いたときだけ0から始めるのが安全。ファーストビューに置く場合は、observer が即座に発火してページ読み込みの慌ただしさと重なるため、少し遅延させると落ち着く。

アクセシビリティ

刻々と変わる数値が live region に入っていると、スクリーンリーダーが中間値を延々と読み上げることになる。アニメーションする要素には aria-hidden="true" を付け、最終値を持つ静的な要素(sr-only)を併置してそちらを読ませる。prefers-reduced-motion: reduce では、カウントアップをせず最初から最終値を表示する。この対応は単に演出を省くだけでなく、動く数字を目で追うのが負担になるユーザーにとって実質的な改善になる。数字だけを大きく出して単位や説明を小さくしすぎると、拡大表示のユーザーが文脈を見失いやすい。「1,200」ではなく「導入企業 1,200社」のように、数値と意味が同じ塊として読める順序でマークアップしておきたい。

調整して使う

触る値は持続時間・イージング・開始のタイミング。持続時間は1.2〜2秒が読みやすい範囲で、桁数が多い数字ほど長め(ただし2.5秒まで)にする。イージングは終盤を緩める ease-out 系にすると着地感が出る。線形だと最後まで同じ速さで動き、止まった瞬間が唐突に見える。複数の数字を並べるときは開始を100〜200msずつずらすと、左から順に読ませる流れが作れる。接頭・接尾の単位(「¥」「万件」「%」)はカウントさせず静的に置くのが基本で、数字部分だけを tabular-nums にして幅を固定する。増加を強調したいなら、着地の瞬間に色を一瞬明るくするか、わずかな scale のバウンドを足すと「到達した」感触が加わる。

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

<div class="scroll-hint">↓ スクロール ↓</div>
<div class="count-block">
  <!-- 動く数字は aria-hidden。読み上げ用の最終値は下の sr-only に置く -->
  <div class="counter" data-target="1280" aria-hidden="true">1,280</div>
  <p class="counter-cap"><span class="sr-only">1,280 </span>ダウンロード数</p>
</div>

タグ

同じカテゴリ「スクロールアニメーション」のほかのパーツ

関連パーツ