こんにちは。KOUKIです。
本記事は、Udemyの「50 Projects In 50 Days – HTML, CSS & JavaScript」で学習したことを載せています。
<目次>
実装するもの
今回は、setTimeoutメソッドを使って、カウンター処理を実装します。
demoは「こちら」で確認できます。
環境構築
簡単な環境構築をお願いします。
必要なファイルは、以下の通りです。
1 2 3 4 5 6 |
$ tree . ├── index.html ├── script.js └── style.css |
CSS版
ページ(HTML)の作成
最初にページを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" /> <link rel="stylesheet" href="style.css" /> <title>Increment Counter</title> </head> <body> <div class="counter-container"> <i class="fab fa-twitter fa-3x"></i> <div class="counter" data-target="12000"></div> <span>Twitter Followers</span> </div> <div class="counter-container"> <i class="fab fa-youtube fa-3x"></i> <div class="counter" data-target="5000"></div> <span>YouTube Subscribers</span> </div> <div class="counter-container"> <i class="fab fa-facebook fa-3x"></i> <div class="counter" data-target="7500"></div> <span>Facebook Fans</span> </div> <script src="script.js"></script> </body> </html> |
このHTMLをブラウザ上で表示すると以下のようになります。

TwitterやYouTube、Facebookのアイコンは、Font Awesomeを使っています。
スタイル(CSS)を装飾
次にスタイルを記述しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@import url('https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap'); * { box-sizing: border-box; } body { background-color: #8e44ad; color: #fff; font-family: 'Roboto Mono', sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; overflow: hidden; margin: 0; } .counter-container { display: flex; flex-direction: column; justify-content: center; text-align: center; margin: 30px 50px; } .counter { font-size: 60px; margin-top: 10px; } @media (max-width: 580px) { body { flex-direction: column; } } |
ここまで実装すると以下のようになります。

補足: box-sizingプロパティについて
「box-sizing」について、少し触れておきましょう。
box-sizingは、ボックスサイズの算出方法を指定する際に使用します。
例えば、div要素で作成したBoxが2つあるとします。
box-sizing: content-box; を指定
box-sizing: border-box; を指定
このボックス要素には、margin、border、padding、テキストエリアの4つの領域を持ちます。box-sizingはボックスサイズを決める時、この領域の内、borderとpaddinigを含めるか否かを指定できるプロパティです。

指定できる値は、全部で3つあります。
1. content-box: paddingとborderを幅と高さに含めない(初期値)
2. border-box: paddingとborderを幅と高さに含める
3. inherit: 親要素の値を継承する
今回は、border-boxを指定しているので、paddingとborderを幅と高さに含めています。つまり、width:300px、 height:300pxの幅に指定するとボックスの大きさはそのまま横300px、縦300pxになります。
一方、content-boxを指定すると、仮にpaddingが10px、borderが5pxの幅を持っていた場合、それぞれ横315px、縦315pxのボックスサイズになります。
JavaScriptでカウンターの実装
準備ができたので、早速、JavaScriptをカウンター処理を実装しましょう。
要素の取得
JavaScriptで制御すべき要素が1つあります。最初にこの要素を取得します。
1 2 |
// 要素を取得する const counters = document.querySelectorAll('.counter') |
HTML属性の取得
HTMLの要素に「data-target」属性をつけているので、この要素に対して操作を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 取得した要素分だけループする counters.forEach(counter => { // カウンターの初期値 counter.innerText = '0' // カウンター更新 const updateCounter = () => { // 属性の取得 const target = counter.getAttribute('data-target') console.log(typeof target, target) } updateCounter() }) |
HTMLに設定された属性は、getAttributeで取得できます。

「string 12000 string 5000 string 7500」とコンソールに出力されたので、属性は取得できたようですね。
ただし、全て「string」型で取得されているので、これを「number」型に変換したいと思います。
string -> numberへの型変換の方法はいくつかありますが、今回は「+」を使います。
1 2 3 4 5 6 7 8 9 10 |
counters.forEach(counter => { ... const updateCounter = () => { // counterの前に「+」をつけるとnumber型で取得できる const target = +counter.getAttribute('data-target') console.log(typeof target, target) } ... }) |
これだけで、number型へ型変換できます。

カウント処理
次は、カウント処理を実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
counters.forEach(counter => { // カウンターの初期値 // カウンター更新 const updateCounter = () => { // 属性の取得 // counter値(0)を格納 const c = +counter.innerText // カウント const increment = target / 200 // targetは最大カウント数 if(c < target) { // 四捨五入する(37.8 -> 38にする) counter.innerText = `${Math.ceil(c + increment)}` } } updateCounter() }) |
HTMLのdata-target属性は、カウンターの最大値です。この値になるまで値を増加させていきます。
の200は別の値でも構いません。この値は、カウンターの増加スピードを制御しているので、色々変えてみてください。const increment = target / 200
Math.ceil()
関数は、引数として与えた数以上の最小の整数を返します。つまり、四捨五入してくれます。
setTimeoutでループ処理
最後に、setTimeoutを使ってループ処理をしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 取得した要素分だけループする counters.forEach(counter => { ... if(c < target) { // 四捨五入する(37.8 -> 38にする) // 1msごとにupdateCouunterをストップ setTimeout(updateCounter, 1) } else { // 最大値を超えた場合は、最大値を設定 counter.innerText = target } updateCounter() }) |
これで完成です。
setTimeoutは、指定時間経過後に、引数に指定した関数(ここではupdateCounter)を実行します。そのため、updateCounterが実行されるたびにsetTimeoutがセットされるので、updateCounterが実行され続けます。
そして、target(最大値)を超えた時、setTimeoutはスキップされるので、タイマーが止まるという仕組みです。
おわりに
setTimeoutのループ処理は、勉強になりましたね。
setIntervalとのコンボで使う機会がありましたが、単体でもループ処理を実現できるのは目から鱗でした^^
それでは、また!
JavaScriptまとめ
JavaScript ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// 要素を取得する const counters = document.querySelectorAll('.counter') // 取得した要素分だけループする counters.forEach(counter => { // カウンターの初期値 counter.innerText = '0' // カウンター更新 const updateCounter = () => { // 属性の取得 const target = +counter.getAttribute('data-target') // counter値(0)を格納 const c = +counter.innerText // カウント const increment = target / 200 // targetは最大カウント数 if(c < target) { // 四捨五入する(37.8 -> 38にする) counter.innerText = `${Math.ceil(c + increment)}` // 1msごとにupdateCouunterをストップ setTimeout(updateCounter, 1) } else { // 最大値を超えた場合は、最大値を設定 counter.innerText = target } } updateCounter() }) |
コメントを残す
コメントを投稿するにはログインしてください。