Voorleesmarkering New
A highlighter moves through the text word by word at reading pace, with a play button and speed control. For explanations paired with audio or video, or to make long copy easier to read.
Voorlezen0:00
Na de opname ontvangt u binnen twee werkdagen een offerte met een vaste prijs. Daarin staat precies welk materiaal we gebruiken, hoeveel dagen we nodig hebben en wanneer we kunnen starten. Meerwerk bespreken we altijd eerst met u, nooit achteraf op de factuur.
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.
<!-- Voorleesmarkering · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="rah"><div class="rah__top"><button class="rah__play" type="button" aria-label="Pauzeer voorlezen"><svg viewBox="0 0 12 12" width="11" height="11" aria-hidden="true"><path class="rah__ip" d="M3 1.5v9l7.5-4.5z"/><g class="rah__ia"><rect x="2.5" y="1.5" width="2.5" height="9"/><rect x="7" y="1.5" width="2.5" height="9"/></g></svg></button><span class="rah__lbl">Voorlezen</span><span class="rah__time">0:00</span><button class="rah__sp" type="button" aria-label="Snelheid">1x</button></div>
<p class="rah__p">Na de opname ontvangt u binnen twee werkdagen een offerte met een vaste prijs. Daarin staat precies welk materiaal we gebruiken, hoeveel dagen we nodig hebben en wanneer we kunnen starten. Meerwerk bespreken we altijd eerst met u, nooit achteraf op de factuur.</p></div>
</div>/* Voorleesmarkering · NedDev · eigen werk. */
.rah{position:absolute;inset:0;background:#fff;color:#0a0a0a;font-family:'Switzer',system-ui,sans-serif;padding:16px 18px;display:flex;flex-direction:column;gap:10px;container-type:inline-size}
.rah__top{display:flex;align-items:center;gap:8px}
.rah__play{appearance:none;width:28px;height:28px;border-radius:50%;border:0;background:#0a0a0a;color:#fff;display:grid;place-items:center;cursor:pointer;transition:transform .2s,background .2s}
.rah__play:hover{background:#F5480F}.rah__play:active{transform:scale(.92)}.rah__play:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.rah__play svg{fill:currentColor}.rah__ia{display:none}.rah.is-on .rah__ia{display:inline}.rah.is-on .rah__ip{display:none}
.rah__lbl{font:500 10px 'JetBrains Mono',monospace;letter-spacing:.1em;text-transform:uppercase;color:#6b6762}
.rah__time{font:500 10px 'JetBrains Mono',monospace;color:#0a0a0a;font-variant-numeric:tabular-nums;margin-right:auto}
.rah__sp{appearance:none;border:1px solid #dcd8d2;background:#fff;border-radius:999px;font:600 10px 'JetBrains Mono',monospace;padding:4px 8px;cursor:pointer;min-width:42px}
.rah__sp:hover{border-color:#0a0a0a}.rah__sp:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.rah__p{position:relative;margin:0;font-size:clamp(12.5px,4.1cqw,15.5px);line-height:1.62;font-weight:500;letter-spacing:-.005em}
.rah__w{position:relative;z-index:1;color:#b3aea7;transition:color .25s;cursor:pointer}
.rah__w.is-read{color:#0a0a0a}.rah__w.is-cur{color:#0a0a0a}
.rah__mk{position:absolute;z-index:0;left:0;top:0;height:1.3em;background:rgba(245,72,15,.2);border-bottom:2px solid #F5480F;border-radius:2px;transition:transform .16s cubic-bezier(.3,.7,.3,1),width .16s cubic-bezier(.3,.7,.3,1);pointer-events:none}
.rah__mk.is-jump{transition:none}
@media (prefers-reduced-motion:reduce){.rah__mk{transition:none}}// Voorleesmarkering · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root=root.querySelector('.rah')||root;
var p=root.querySelector('.rah__p'),play=root.querySelector('.rah__play'),sp=root.querySelector('.rah__sp'),tm=root.querySelector('.rah__time');
var rm=matchMedia('(prefers-reduced-motion: reduce)').matches;
var words=p.textContent.trim().split(/\s+/);p.innerHTML='';
var ws=words.map(function(w,i){var s=document.createElement('span');s.className='rah__w';s.textContent=w;p.appendChild(s);p.appendChild(document.createTextNode(' '));return s;});
var mk=document.createElement('span');mk.className='rah__mk';mk.setAttribute('aria-hidden','true');p.insertBefore(mk,p.firstChild);
var i=-1,on=false,speed=1,timer=0,lastTop=null,elapsed=0;
function place(k){var w=ws[k];if(!w){mk.style.width='0px';return;}var top=w.offsetTop-1;mk.classList.toggle('is-jump',lastTop!==null&&top!==lastTop);lastTop=top;mk.style.transform='translate('+(w.offsetLeft-2)+'px,'+top+'px)';mk.style.width=(w.offsetWidth+4)+'px';}
function mark(k){i=k;ws.forEach(function(w,j){w.classList.toggle('is-read',j<k);w.classList.toggle('is-cur',j===k);});place(k);}
function dur(k){return (170+ws[k].textContent.length*30)/speed;}
function fmt(ms){var s=Math.floor(ms/1000);return Math.floor(s/60)+':'+('0'+s%60).slice(-2);}
function step(){if(!on)return;if(i>=ws.length-1){timer=setTimeout(function(){elapsed=0;mark(0);timer=setTimeout(step,dur(0));},1600);return;}var d=dur(i+1);mark(i+1);elapsed+=d;tm.textContent=fmt(elapsed);timer=setTimeout(step,d);}
function setOn(v){on=v;root.classList.toggle('is-on',v);play.setAttribute('aria-label',v?'Pauzeer voorlezen':'Start voorlezen');clearTimeout(timer);if(v)step();}
play.addEventListener('click',function(){setOn(!on);});
sp.addEventListener('click',function(){speed=speed===1?1.5:speed===1.5?2:1;sp.textContent=speed+'x';});
ws.forEach(function(w,k){w.addEventListener('click',function(){clearTimeout(timer);mark(k);if(on)timer=setTimeout(step,dur(k));});});
window.addEventListener('resize',function(){lastTop=null;place(i);});
mark(0);setOn(!rm);if(rm){play.setAttribute('aria-label','Start voorlezen');}
}
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 →