本文へスキップ
HELLO!
HIGASHIYUKI®.COM
0   /   100
グラフ

スクロールで実績の数字がカウントアップする

デモ

操作:スクロール。 「さわってみる」を押すと自動再生が止まり、マウスで動かせます。 触っている間は、ホイールでデモの中がスクロールします。

仕様

用途
グラフ
動作
DOM
種類
レシピ
使うもの
ScrollTrigger
動作確認
three 0.186.0・gsap 3.15.0
公開日

しくみと調整

数字そのものではなく、0 から目標値へ動く値をひとつ用意して補間し、その値を毎コマ丸めて書き出します。桁区切りは toLocaleString に任せるので、1,280 のような表記のまま数えられます。単位は数字の後ろの別の要素に置き、数字の要素だけを書き換えます。

1.6 秒の power2.out で数えます。終わりに向けてゆっくりになるので、最後の数桁まで読み取れます。まっすぐ数えると、止まる瞬間まで数字が速いままで、いくつで止まったのかが分かりません。

数字には tabular-nums を指定してください。ふつうの字形では 1 と 8 で幅が違うので、数えているあいだ数字の列が左右に揺れます。単位を数字と同じ要素に入れたままにすると、書き換えのたびに単位も消えてしまいます。

数え始める線は画面の下から 2 割ほど内側に置き、一度数えたらそれきりにします(once)。上下に往復するたびに数え直すと、数字がいつまでも定まらないように見えます。

実績・利用者数・料金の節など、数字そのものを主役にしたい所に向いています。桁が多いほど効くので、2 桁ほどの小さな数字は、数えずに出したほうが落ち着きます。

コード

HTML
<section class="stats" aria-labelledby="stats-title">
  <h2 class="stats__title" id="stats-title">Numbers</h2>

  <dl class="stats__list">
    <!-- 説明(dt)→ 数字(dd)の順に書き、見た目の上下だけ CSS で入れ替える -->
    <div class="stat">
      <dt class="stat__label">これまでの制作実績</dt>
      <dd class="stat__value">
        <!-- 目標値は data 属性に。中身は書き換えるので、最初は 0 を置いておく -->
        <span class="stat__number" data-count-to="1280">0</span><span class="stat__unit">件</span>
      </dd>
    </div>

    <div class="stat">
      <dt class="stat__label">お客さまの継続率</dt>
      <dd class="stat__value">
        <span class="stat__number" data-count-to="98">0</span><span class="stat__unit">%</span>
      </dd>
    </div>

    <div class="stat">
      <dt class="stat__label">ご利用いただいている国</dt>
      <dd class="stat__value">
        <span class="stat__number" data-count-to="36">0</span><span class="stat__unit">か国</span>
      </dd>
    </div>
  </dl>
</section>
CSS
.stats {
  --ink: #eeece6;
  --mute: #898989;
  padding: 18vh 6vw;
  background-color: #111111;
  color: var(--ink);
  text-align: center;
}

.stats__title {
  margin: 0 0 48px;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mute);
}

.stats__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px;
  margin: 0;
}

/* 書く順は dt → dd のまま、見た目だけ数字を上にする */
.stat {
  display: flex;
  flex-direction: column-reverse;
}

.stat__value {
  margin: 0;
  /* 1 と 8 で幅が変わらない数字。字形が変わると、数えるあいだ列が左右に揺れる */
  font-variant-numeric: tabular-nums;
  font-size: clamp(44px, 5.6vw, 72px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

/* 単位は別の要素。数字だけを書き換えるので、単位は消えない */
.stat__unit {
  margin-left: 4px;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.stat__label {
  margin-top: 16px;
  font-size: 18px;
  line-height: 1.8;
  letter-spacing: 0.04em;
  color: var(--mute);
}
JavaScript
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
// 数えている値を、毎コマ丸めて書き出す。桁区切りは toLocaleString に任せる
const write = (el, value) => (el.textContent = Math.round(value).toLocaleString("ja-JP"));

document.querySelectorAll(".stats").forEach((stats) => {
  const list = stats.querySelector(".stats__list");
  const counters = gsap.utils
    .toArray(".stat__number", stats)
    .map((el) => ({ el, target: Number(el.dataset.countTo) }));

  // 動きを減らす設定では、数えずに最後の値を出す
  if (reduceMotion) {
    counters.forEach(({ el, target }) => write(el, target));
    return;
  }

  gsap.set(list, { y: 32, opacity: 0 });
  ScrollTrigger.create({
    trigger: stats,
    start: "top 80%", // 画面の下から 2 割ほど内側に入ったら数え始める
    once: true, // 一度数えたらそれきり。上下に往復するたびに数え直さない
    onEnter: () => {
      gsap.to(list, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out" });
      counters.forEach(({ el, target }) => {
        const state = { value: 0 };
        gsap.to(state, {
          value: target,
          duration: 1.6,
          ease: "power2.out", // 終わりに向けてゆっくりになるので、最後の数桁まで読み取れる
          onUpdate: () => write(el, state.value),
        });
      });
    },
  });
});

インタラクションデザインについて、
お気軽にご相談ください。

ここに並べているのは、Web サイトの中で動く UI のサンプルです。新しく作るサイトに組み込むことも、いま公開中のサイトに、ボタンやヒーロー、スクロールの演出だけを足すこともできます。設計から実装までの進め方はWeb サイト制作、端末ごとの見え方や表示速度の考え方はレスポンシブウェブサイトのページにまとめています。映像として作る動きをお探しの場合はモーショングラフィックスをご覧ください。