You must have come across different blog/news article websites with progress bar at the top of the page, which keeps on changing as you scroll through the whole page. Here, we will see how to implement it using HTML, CSS, and simple JavaScript.
You may directly access the codepen here.
First, add an empty div with id progressBar right after the opening body tag in HTML markup. This markup will stay fixed at the top of our page. To achieve that, let’s add some CSS properties to it.
<div class="progressBar"></div>
The div is initially empty, so any changes in the width of the indicator will affect the width of the whole div (aka the progress bar). Starting with a width:0
, we will calculate and vary the style of this width, as we scroll through the whole page using JavaScript.
.progressBar {
position: fixed;
top: 0;
left: 0;
height: 8px;
background: linear-gradient(to right, #ff5f6d, #ffc371);
width: 0%;
z-index: 100;
transition: width 0.2s ease-out;
}
Let’s talk about the fun part, adding the JavaScript.
We select progressBar
id and section
selector. Then pass them as parameters in document method querySelector()
which returns the first element within the document that matches the specified selector.
const progressBar = document.querySelector('.progressBar');
const section = document.querySelector('section');
Now declare an arrow function named scrollProgressBar
, within which we make a few calculations. As scrollDistance
defines the size of the section and its position relative to the viewport. Although in our case, we only need the top distance so we write section.getBoundingClientRect().top
. As we need to convert this value into a percentage later, a positive value will be the best fit to work with.
let scrollDistance = -(section.getBoundingClientRect().top);
We could’ve used good old Math.abs()
method to return the absolute value of the top, instead we will take the negative(-ve) value of it, to convert it into a positive value. While implementing further logic for the scroll bar we will find out why.
Imagine the complete rectangle is the viewport of the website. In the beginning, the viewport stays at the top of the webpage, when the width of the progress bar is at width:0
. If the webpage is scrollable enough then page length exceeds the viewport height and our scrollProgressBar
function kicks in.
After that, progressPercentage will be calculated using the following formula:
where, the numerator represents how much distance of the webpage has already been scrolled through and the denominator defines how much scroll distance is remaining to reach the end of the webpage.
Now one problem may arise that viewport height is the top viewport height so it never really reaches the bottom of the page. Thus, we need to subtract the document height from the section height.
Multiplying this fraction to 100 will eventually generate the percentage index for the progress bar.
Applying
Math.floor()
on it returns the largest integer less than or equal to the decimal value.
let progressPercentage =(scrollDistance/(section.getBoundingClientRect().height - document.documentElement.clientHeight)) * 100;
let val = Math.floor(progressPercentage);
With the help of this val
, we calculate the width styling of the progress bar using the HTML DOM (that allows JavaScript to change the style of HTML elements) by concatenating it with the ‘%’
sign.
progressBar.style.width = val + '%';
Adding scroll event to the event listener finally gives the increase in progress bar width as the user scrolls through the page.
window.addEventListener('scroll', scrollProgressBar);
Up to this point have to realize why using Math.abs()
is not a clever idea. It is simply because the scrollDistance
never really reaches zero value (0). So for our convenience, we convert it to zero (0) for any value of val < 0
.
if (val < 0) {
progressBar.style.width = '0%';
}
The complete code look something like:
const progressBar = document.querySelector('.progressBar');
const section = document.querySelector('section');
const scrollProgressBar = () => {
let scrollDistance = -(section.getBoundingClientRect().top);
let progressPercentage =
(scrollDistance /
(section.getBoundingClientRect().height -
document.documentElement.clientHeight)) * 100;
let val = Math.floor(progressPercentage);
progressBar.style.width = val + '%';
if (val < 0) {
progressBar.style.width = '0%';
}
};
window.addEventListener('scroll', scrollProgressBar);
Now, if all the steps are done correctly you should see your very own progress bar animation as you scroll through the website, no matter what is the size of your screen, which means it is completely responsive.
Top comments (2)
Create Scroll Progress Indicator on blog/website
Sh Raj ・ Mar 27
Thank you for this tutorial!