
こんにちは、エンジニアの六川です。
2026年になりました。新たな年の幕開けですね!
私は寒がりなので冬があまり得意ではないのですが、今年は職場の皆さんから、誕生日プレゼントとしてマフラーをいただいたので、あたたかい冬が過ごせそうです。
さて今回は、数字をカウントアップさせるアニメーションの作り方をご紹介したいと思います。
カウントアップアニメーションを使うと、任意の値を動的に表現できるので、サイトのアクセントとしても効果的です。
参考:HANARIA(https://hanaria.jp/)
本記事では、JavaScriptライブラリの一種GSAPを用いて「特定の位置に到達したら、任意の値をカウントアップさせる」という仕組みを実装していきます。
私なりに噛み砕いて解説しているので、よろしければ最後までご覧ください。
Table of contents
コードの全体図
まずはコードの全体図を確認しましょう。
<section data-countup-trigger> <h1>Year</h1> <p data-countup-target data-from="0" data-to="2026">0</p> </section>
const countUpTrigger = document.querySelector('[data-countup-trigger]');
const countUpTargets = document.querySelectorAll('[data-countup-target]');
countUpTargets.forEach( target =>{
const countElement = {
from: target.dataset.from,
to: target.dataset.to
}
const numberElement = {
count: countElement.from
}
gsap.to(numberElement, {
count: countElement.to,
duration: 2,
ease: "power4.out",
scrollTrigger: {
markers: true,
trigger: countUpTrigger,
start: 'top center',
},
onUpdate:()=>{
target.textContent = Math.floor(numberElement.count) ;
}
})
})
コードの解説
大まかな流れは下記のとおりです。順を追って説明していきます。
- HTMLにdata属性で開始値、終了値を指定する
- data属性をJavaScriptで取得する
- GSAPを使って、取得した値を1つずつ繰り上げる
1.HTMLにdata属性で開始値、終了値を指定する
まずは、どの値からどの値までカウントアップさせるかをHTML側で指定します。
今回はdata属性を使って、data-toに開始値、data-fromに終了値を指定しました。data属性を使うことで、その値をJavaScriptで取得することができます。
<section data-countup-trigger> <h1>Year</h1> <p data-countup-target data-from="0" data-to="2026">0</p> </section>
2.data属性をJavaScriptで取得する
次に、HTMLで設定したdata属性の値を取得してみましょう。data属性はdatasetプロパティを使うことで取得できます。
下記のように、属性名の data- より後の部分を使用して取得します。
const countUpTargets = document.querySelectorAll('[data-countup-target]');
console.log(countUpTargets.dataset.from); // 0
console.log(countUpTargets.dataset.to); // 2026
それぞれの値が取得できましたね。
3.GSAPを使って、取得した値を1つずつ繰り上げる
次はいよいよGSAPの出番です。
今回はスクロールをトリガーとして、可視領域に入ったらカウントアップを発動させたいと思います。
まずは、要素の数だけアニメーションを動作させたいので、forEach を使ってトリガーの数だけループさせます。
2のデータ属性で取得した値も、扱いやすいようにオブジェクトとして格納しておきましょう。
const countUpTargets = document.querySelectorAll('[data-countup-target]');
countUpTargets.forEach( target =>{
const countElement = {
from: target.dataset.from,
to: target.dataset.to
}
})
続いて、gsap.to() を使って、具体的な動きを指定しましょう。
GSAPでは、第1引数には対象とする要素、第2引数にはプロパティと値を指定します。
- GSAPアニメーションの具体例
下記の場合、第1引数には’.target’を持つ要素を指定し、第2引数にはxプロパティに50、durationプロパティに2を指定しています。// '.target'を持つ要素を右に50px、2秒かけて移動させる gsap.to('.target', { x: 50, duration: 2, })scrollTriggerでアニメーションの開始位置を指定することも可能です。startプロパティには、トリガー要素のどの位置が画面のどの位置に来たらアニメーションを開始するかを指定します。
// '.target'を持つ要素の中心(1つ目のcenter)が画面の中心(2つ目のcenter)に来たら、右に50px移動させる gsap.to('.target', { x: 50, scrollTrigger: { trigger: '.target', start: 'center center', } })
今回の場合、data属性で指定した開始値から終了値までをカウントさせたいので、第1引数にnumberElement、第2引数にcountプロパティを指定します。
countUpTriggerをトリガーとして、要素の上部が画面の中央に来たら一斉にアニメーションが開始されます。
const numberElement = {
count: countElement.from
} ;
gsap.to(numberElement, { // アニメーションさせたい要素(numberElement)
count: countElement.to, // 終了値
duration: 2, // アニメーションの時間(秒)
ease: "power4.out", // イージングの種類
scrollTrigger: {
trigger: countUpTrigger, // トリガーとなる要素
start: 'top center', // トリガーの開始位置
}
})
最後に、コールバックを指定します。onUpdateは、アニメーション中に数字が更新されるたび(1秒間に約60回)に実行される関数です。GSAPは裏側で変数の値を書き換えるだけなので、そのままでは画面上の表示は変わりません。
そのため、onUpdateを使って、更新された最新の数字を target.textContent にその都度上書きしてあげる必要があります。
また、GSAPは滑らかに動かすために小数の状態で計算を進めます。そのまま表示すると「1.2345…」のように表示されてしまうため、Math.floor(または Math.trunc)を使って整数に整えてから画面に出しましょう。
onUpdate:()=>{
countUpTarget.textContent = Math.floor(numberElement.count) ;
}
- Math.floorとは
引数として与えられた数値以下の最大の整数を返すメソッドです。
例えば、Math.floor(2.7)は2を返します。
ちなみに、最後のonUpdateにて toLocaleString()を追加することで、数字をカンマ区切りにすることもできます。
countUpTarget.textContent = Math.floor(numberElement.count).toLocaleString() ; // 2,026
完成!
完成したアニメーションはこちら。
おわりに
いかがでしたか。GSAPを用いることで、スクロール位置に応じたアニメーションを簡単に実装することができます。
ぜひ皆さんのサイトでも取り入れてみてくださいね。