Getal telt op in de zin New
Numbers in the middle of a running sentence count up to their final value, with Dutch thousands separators and an underline that grows along. Each number's width is fixed beforehand, so the sentence never shifts. For an about or results paragraph; screen readers read the final number straight away.
Sinds 2009 plaatste Dakkapel Direct 3.482 dakkapellen in Zwolle en omgeving. Dit jaar waren het er al 214, met een gemiddelde levertijd van 9 werkdagen.
How to use it
- Paste the HTML where the text animations should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Getal telt op in de zin · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="giz">
<p class="giz__p">Sinds 2009 plaatste Dakkapel Direct <span class="giz__n" data-to="3482">3.482</span> dakkapellen in Zwolle en omgeving. Dit jaar waren het er al <span class="giz__n" data-to="214">214</span>, met een gemiddelde levertijd van <span class="giz__n" data-to="9">9</span> werkdagen.</p>
<button class="giz__knop" type="button">Opnieuw tellen</button>
</div>
</div>/* Getal telt op in de zin · NedDev · eigen werk. */
.giz{position:absolute;inset:0;container-type:inline-size;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:14px;padding:16px 22px;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#f4f3f1;text-align:left}
.giz__p{margin:0;font-size:clamp(16px,4.8cqw,21px);font-weight:500;line-height:1.45;letter-spacing:-.01em}
.giz__n{font-weight:700;font-variant-numeric:tabular-nums}
.giz__sr{user-select:none;position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.giz__v{display:inline-block;text-align:right;background:linear-gradient(#F5480F,#F5480F) 0 100%/var(--p,100%) 3px no-repeat;padding-bottom:1px}
.giz__knop{min-height:28px;padding:5px 10px;border:1px solid rgba(10,10,10,.25);border-radius:4px;background:#fff;color:#0a0a0a;font:500 12px/1 'Switzer',system-ui,sans-serif;cursor:pointer}
.giz__knop:hover{border-color:#0a0a0a}
.giz__knop:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.giz__knop{display:none}}// Getal telt op in de zin · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
const w = root.querySelector('.giz'); if (!w) return;
const fmt = n => Math.round(n).toLocaleString('nl-NL');
const nums = [...w.querySelectorAll('.giz__n')].map(n => {
const doel = +n.dataset.to; n.textContent = '';
const sr = document.createElement('span'); sr.className = 'giz__sr'; sr.textContent = fmt(doel);
const v = document.createElement('span'); v.className = 'giz__v'; v.setAttribute('aria-hidden', 'true'); v.textContent = fmt(doel);
n.append(sr, v);
return { v, doel };
});
const maat = () => nums.forEach(o => { o.v.style.minWidth = ''; o.v.textContent = fmt(o.doel); o.v.style.minWidth = o.v.getBoundingClientRect().width + 'px'; });
maat();
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
let raf = 0;
const tel = () => {
cancelAnimationFrame(raf); maat();
const start = performance.now(), duur = 1700;
const f = nu => {
const t = Math.min((nu - start) / duur, 1), e = 1 - Math.pow(1 - t, 3);
nums.forEach(o => { o.v.textContent = fmt(o.doel * e); o.v.style.setProperty('--p', (e * 100) + '%'); });
if (t < 1) raf = requestAnimationFrame(f);
};
raf = requestAnimationFrame(f);
};
if ('IntersectionObserver' in window) {
const io = new IntersectionObserver(e => { if (e[0].isIntersecting) { tel(); io.disconnect(); } }, { threshold: .5 });
io.observe(w);
}
w.querySelector('.giz__knop').addEventListener('click', tel);
}
init(document.querySelector('.jouw-container'));
More text animations
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →