DEV Community

Cover image for Create a Reading Scroll Progress Bar for Your Blog in JavaScript and CSS
Gabe Romualdo
Gabe Romualdo

Posted on • Updated on • Originally published at

Create a Reading Scroll Progress Bar for Your Blog in JavaScript and CSS

This post is originally from, a blog about CSS, JavaScript, and just about anything programming.

Go check out Daily Developer Jokes, my latest project!

Daily Developer Jokes Website
Follow Daily Developer Jokes on DEV

Here's the joke from today:

Daily Developer Jokes, Friday Feb. 5, 2020

I just recently added a fun little feature on my website at a progress bar when reading blog posts. The bar would show how far users have progressed in reading a post, from 0% at the beginning to when a user finishes reading at 100%.

This little feature has become particularly popular among other blogs and Wordpress themes in recent years. For example, the popular tech publication TechCrunch uses a circular scroll progress bar, and many other sites have a similar feature. In fact, if you're reading this on, then you may be able to see this feature on the top of your screen!

Below is a quick tutorial and explanation of a horizontal scroll progress bar with a demo on CodePen.

Live Demo and Final CodePen

Before we start, here is a link to the final CodePen, and again, a live demo can be seen on my personal website, if you are on desktop. Here's the final result of this:

Final Demo

Writing the HTML & CSS

To start off, let's create a post container div, which will include the HTML contents of the blog post that your viewers will be reading. Within that div, we'll also include a progress bar element for the scroll progress bar.

<div class="post_container"></div>
Enter fullscreen mode Exit fullscreen mode

At the beginning of the post container element, let's add the progress bar HTML, which will look like this:

<div class="post-container">
    <div class="progress-bar-container">
        <div class="progress-bar-container__progress"></div>
Enter fullscreen mode Exit fullscreen mode

Note that in this post, I'll be using the BEM Methadology for CSS classnames. You can read more about the BEM Methadology and what it is here: How I Moved a Step Closer to Clean CSS and How You Can Too (with the BEM Methodology).

The general idea here is to have the progress bar container fixed at the top of the post container, with a full width. Within that container, the actual progress bar can be resized to the correct width with JavaScript.

Progress Bar and Container Visual

Here is the basic CSS for this:

/* default CSS variables */
:root {
    --progress-color: #2ecc71;
    --progress-height: .5rem;

/* post container */
.post-container {
    overflow: scroll;

/* progress bar container */
.progress-bar-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: var(--progress-height);

/* progress bar */
.progress-bar-container > .progress {
    height: var(--progress-height);
    background-color: var(--progress-color);
    width: 0%;
    float: left;
Enter fullscreen mode Exit fullscreen mode

Note that in this case, the CSS assumes that the .post-container element is the scrollable area in this case (as defined with the overflow: scroll line), but you can change this to be a different element or the body element yourself if you'd like.

I'm also using CSS variables for the progress bar height and color, so that it is easier to change the properties of the progress bar if you'd like. You can read more about CSS variables and what they are here: CSS Variables Explained in 2 Minutes with an Interactive Demo.

Here's what this looks like when I set the width to 50% for example (with example content in the post container):

50% Scroll Progress Bar Width Example

Let's Write the JavaScript for this!

For the JavaScript, I'll start by defining variables for each of the relevant HTML elements:

// variables for progress bar and post container elements
const progressContainerEl = document.querySelector(".post-container");
const progressBarEl = document.querySelector(".progress-bar-container__progress");
Enter fullscreen mode Exit fullscreen mode

Creating a Function to Update the Progress Bar Width

Let's create a function which checks the current scroll position and calculates the percentage of the post read, and then set the progress bar width accordingly.

To make the scroll percentage calculation, let's divide the current scroll position (from the scrollTop property) by the full scroll height of the element (calculated with a function I got from Stack Overflow).

I then set the width style of the progress bar element to that calculated percentage.

Here's the code for that:

// function to check scroll position and update scroll progress bar accordingly
const updateScrollProgressBar = () => {
    // get full scroll height
    const scrollHeight = progressContainerEl.scrollHeight - heightInViewport(progressContainerEl);
    // get current scroll position
    const scrollPosition = progressContainerEl.scrollTop;

    // get scroll percentage and set width of progress bar
    const scrollPercentage = (scrollPosition / scrollHeight) * 100; = scrollPercentage + "%";

// function to get visible height in viewport
// some code taken from user Roko C. Buljan on
function heightInViewport(el) {
    var elH = el.offsetHeight,
        H   = document.body.offsetHeight,
        r   = el.getBoundingClientRect(),, b=r.bottom;
    return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
Enter fullscreen mode Exit fullscreen mode

Calling the Function While Scrolling

To put all of this together and make everything work, we'll need to call the function everytime a user scrolls and when the page is loaded. For that, it's possible bind the function to the onscroll event of the post container, and the onload event of the window.

// bind window onload and onscroll events to update scroll progress bar width
progressContainerEl.addEventListener("scroll", updateScrollProgressBar)
progressContainerEl.addEventListener("load", updateScrollProgressBar)
Enter fullscreen mode Exit fullscreen mode

We're Done!

And with that, we're finished. Here is the final CodePen:

I hope you liked this post, and found this to be useful.

Thanks for scrolling.

This post is originally from, a blog about CSS, JavaScript, and just about anything programming.

— Gabriel Romualdo, February 5, 2020

Note: I formerly wrote under my pseudonym, Fred Adams.

Top comments (12)

waylonwalker profile image
Waylon Walker

Very nice... I want to say,

"doesnt the web already come with a progress bar on the side?"

but this looks so good. I would go for it!

tayyebi profile image

Dear Waylon, in some cases, when there is a serial of content, or a lazy loading concept for posts is implemented, the scroll bar will not be feasible (because of later appended content). We solved this issue for video content so far with timeline, and it's nice to have it for text content. Anyway I'm totally agree with you that if there is a single "post" in a "page", it's not a good idea to have a horizontal progress bar.

Hey Fred. That was cool man! Bravo. A minimal code that works. Well done.

xtrp profile image
Gabe Romualdo • Edited

Thanks, I really appreciate that!

— Gabriel

xtrp profile image
Gabe Romualdo • Edited

Thank you! I personally would only use this for articles or longer pages on a site, just to give users a clearer reminder of how long the page is and how far they've read. Thanks again!

— Gabriel

aleksandrhovhannisyan profile image
Aleksandr Hovhannisyan • Edited

Nicely done! It even works in Edge.

That said, I'm not a big fan of BEM. This looks awful to me:


Side note: I once tried adding a reading progress bar to my blog and found it pretty distracting. There's a good discussion about it over on the UX Stack Exchange.

whatthehanan profile image
Hanan Hamza

I personally prefer BEM with scss.

djpandab profile image
Stephen Smith

Good job. I like this!

xtrp profile image
Gabe Romualdo • Edited


— Gabriel

kumareth profile image
Kumar Abhirup

Hey hi! Ur write-up is awesome! I am Kumar Abhirup, teenager JavaScript developer. Check out my profile we have a lot in common ⚡😄

joseluisrnp profile image
José Luis Recio

Cool and simple progress bar!

xtrp profile image
Gabe Romualdo • Edited

Thank you!

— Gabriel

yashwanth2804 profile image
kambala yashwanth

Better If we got this implemented in site articles too.