Ce code ajoute une barre fine et fixe en haut de l’écran qui avance proportionnellement à la progression de lecture d’un élément texte spécifique (par exemple, un article). La barre démarre lorsque le haut du contenu ciblé entre dans la zone visible et atteint 100 % quand le bas du texte arrive au bas du viewport. Entièrement personnalisable via variables CSS (hauteur, couleur, fond, ombre), ce composant est léger, accessible, réactif aux redimensionnements et compatible avec du contenu chargé dynamiquement .
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Barre de lecture</title>
<style>
body{ margin:0; font-family:system-ui,-apple-system,"SF Pro Text",Segoe UI,Roboto,Helvetica,Arial }
/* Barre fixe */
.read-progress{
position:fixed; inset:0 0 auto 0; height:4px; z-index:1000; background:transparent;
}
.read-progress > span{
display:block; height:100%; width:0%;
background: linear-gradient(90deg,#0a84ff,#34c759);
transition: width .08s linear;
}
/* Demo contenu long */
header{ padding:24px 16px }
main{ padding:0 16px 80px; max-width:840px; margin:auto }
p{ line-height:1.65; color:#2b2b2b }
</style>
</head>
<body>
<div class="read-progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-label="Progression de lecture">
<span></span>
</div>
<header><h1>Article très long</h1></header>
<main id="article">
<script>
// génère du faux texte pour la démo
document.write('<p>'+('Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(40))+'</p>'.repeat(40));
</script>
</main>
<script>
(function(){
const bar = document.querySelector('.read-progress > span');
const root = document.documentElement;
let ticking = false;
function compute(){
const max = root.scrollHeight - root.clientHeight;
const p = max ? (root.scrollTop / max) * 100 : 0;
bar.style.width = p + '%';
bar.parentElement.setAttribute('aria-valuenow', Math.round(p));
ticking = false;
}
function onScroll(){
if (!ticking){ ticking = true; requestAnimationFrame(compute); }
}
addEventListener('scroll', onScroll, {passive:true});
addEventListener('resize', onScroll);
compute();
})();
</script>
</body>
</html></script>