Animated Stat Counters
Number counters that ease up to their value when they scroll into view, with prefix/suffix support.
<div class="counts">
<div class="count"><span class="num" data-to="12480">0</span><span class="lbl">Downloads</span></div>
<div class="count"><span class="num" data-to="98" data-suffix="%">0</span><span class="lbl">Satisfaction</span></div>
<div class="count"><span class="num" data-to="340" data-prefix="+">0</span><span class="lbl">Contributors</span></div>
</div>*{box-sizing:border-box}
.counts{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;font-family:system-ui,sans-serif}
.count{background:#fff;border:1px solid #eceef3;border-radius:16px;padding:26px 30px;text-align:center;min-width:140px;box-shadow:0 6px 20px rgba(20,25,50,.06)}
.num{display:block;font-size:38px;font-weight:800;background:linear-gradient(135deg,#ff7a18,#ff477e);-webkit-background-clip:text;background-clip:text;color:transparent}
.lbl{display:block;margin-top:6px;color:#8a91a6;font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}function animate(el){
var to=+el.dataset.to,pre=el.dataset.prefix||'',suf=el.dataset.suffix||'',start=null,dur=1600;
function step(t){if(!start)start=t;var p=Math.min((t-start)/dur,1);var v=Math.floor((1-Math.pow(1-p,3))*to);el.textContent=pre+v.toLocaleString()+suf;if(p<1)requestAnimationFrame(step)}
requestAnimationFrame(step);
}
var io=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting){animate(e.target);io.unobserve(e.target)}})},{threshold:.4});
document.querySelectorAll('.num').forEach(function(n){io.observe(n)});Free to use.This snippet is plain HTML, CSS and JavaScript with no dependencies. Copy any file, or download the whole thing as a single ready-to-open .html page.