スクロール
Anime.js

Anime Scroll Counter

スクロールで表示されたらanime.jsで数値がカウントアップするセクション。

HTML
<div class="asc-wrap">
  <div style="height:80vh;"></div>
  <div class="asc-section" id="asc-section">
    <div class="asc-item"><span class="asc-num" id="asc-n1">0</span><span class="asc-label">Projects</span></div>
    <div class="asc-item"><span class="asc-num" id="asc-n2">0</span><span class="asc-label">Users</span></div>
    <div class="asc-item"><span class="asc-num" id="asc-n3">0</span><span class="asc-label">Stars</span></div>
  </div>
  <div style="height:80vh;"></div>
</div>
CSS
body { padding: 0 !important; }
.asc-wrap { width: 100%; }
.asc-section {
  display: flex;
  gap: 48px;
  justify-content: center;
  padding: 48px 0;
}
.asc-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.asc-num {
  font-size: 36px;
  font-weight: 900;
  color: #6366f1;
}
.asc-label {
  font-size: 13px;
  color: #94a3b8;
  margin-top: 4px;
}
JavaScript
let counted = false;
const section = document.getElementById('asc-section');
const targets = [
  { el: document.getElementById('asc-n1'), val: 120 },
  { el: document.getElementById('asc-n2'), val: 5400 },
  { el: document.getElementById('asc-n3'), val: 890 }
];
function checkScroll() {
  if (counted) return;
  const rect = section.getBoundingClientRect();
  if (rect.top < window.innerHeight * 0.8) {
    counted = true;
    targets.forEach(function(t) {
      anime({
        targets: t,
        val: [0, t.val],
        round: 1,
        duration: 2000,
        easing: 'easeOutExpo',
        update: function() {
          t.el.textContent = Math.floor(t.val).toLocaleString();
        }
      });
    });
  }
}
window.addEventListener('scroll', checkScroll);
checkScroll();