Reading Progress
A copy-paste scroll-driven component in pure HTML & CSS. Zero dependencies, framework-agnostic, MIT-licensed.
Scroll-DrivenHTMLCSSany framework
Scroll this panel.
The top bar tracks how far you have read.
It scales horizontally with scroll progress.
Pure CSS — no script involved.
Keep going to fill the bar.
Copy into your project
HTML
<!-- Reading progress bar driven by page scroll (CSS only) -->
<div class="nuda-scrollpb__track" role="progressbar"
aria-label="Reading progress">
<div class="nuda-scrollpb__bar"></div>
</div>CSS
/* Reading Progress
A top bar that fills as the document scrolls, using a native
scroll-progress timeline. Animates transform: scaleX (GPU only),
never width. Customize: --progress-color, --progress-height */
.nuda-scrollpb__track {
--progress-color: #e4ff54;
--progress-height: 4px;
position: fixed;
inset: 0 0 auto 0;
height: var(--progress-height);
background: rgba(255, 255, 255, 0.06);
z-index: 9999;
}
.nuda-scrollpb__bar {
height: 100%;
background: var(--progress-color);
transform: scaleX(0);
transform-origin: 0 50%;
animation: nuda-scrollpb-fill linear;
animation-timeline: scroll(root block);
}
@keyframes nuda-scrollpb-fill {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Browsers without scroll timelines: leave a faint full bar. */
@supports not (animation-timeline: scroll()) {
.nuda-scrollpb__bar { transform: scaleX(1); opacity: 0.5; }
}
@media (prefers-reduced-motion: reduce) {
.nuda-scrollpb__bar {
animation: none;
animation-timeline: none;
transform: scaleX(1);
}
}How to use Reading Progress
Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.
Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.