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

グラフ

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

デモ

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

仕様

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

しくみと調整

実績の数字は、画面に入ったところで目標の値まで勢いよく数え上がり、終わりに向けてゆっくりになって止まります。アニメーションさせているのは表示の数字ではなく、0から目標値へ変化する値ひとつです。GSAP が補間したその値をフレームごとに整数へ丸めて書き出し、桁区切りは toLocaleString に任せているので、1,280のような表記のまま数えられます。

時間は1.6秒、イージングは power2.out にしました。一定の速さで数えると、止まる瞬間まで数字が速く変わり続け、いくつで止まったのかが読み取れません。数え始める位置は画面の下端から2割ほど内側で、一度数えたら once でそれきりです。往復するたびに数え直すと、数字がいつまでも定まらないように見えます。

数字には tabular-nums を指定してください。通常の字形は数字ごとに幅が違うので、数えている間に数字の列が左右に揺れます。単位は数字の後ろに別の要素として置き、書き換えるのは数字の要素だけにしてあります。同じ要素に入れておくと、書き換えのたびに単位まで消えてしまいます。桁の少ない数字なら、数えずにそのまま表示したほうが落ち着いて見えます。

コード

HTML
<section class="stats" aria-labelledby="stats-title">
  <h2 class="stats__title" id="stats-title">数字で見る実績</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;
  --mute-small: #a8a6a0; /* 16px 未満の文字 */
  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.06em; /* 和文の小さなラベル。英大文字の字間(0.14em)は和文にかけない */
  color: var(--mute-small);
}

.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 サイト制作、端末ごとの見え方や表示速度の考え方はレスポンシブウェブサイトのページにまとめています。映像として作る動きをお探しの場合はモーショングラフィックスをご覧ください。