JavaScript Page Scroll Progress Bar
Tags: javascript, html, css, beginners
Published: 2022-01-12 15:59:15

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.

![Example Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2fil5id0ps70lx9oa9q6.png)
You may directly access the codepen [here](https://codepen.io/sagnik-77/pen/RwLYyzJ).

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.

```html
<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.

```css
.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.

```js
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.

```js
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.


![Viewport Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8hvbkt7hqrt89sebcoy.png)

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:

![Progress Percentage Formula](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjnkrqoqtcw4kxz8opuk.png)
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.

```js
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. 

```js
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.

```js
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`.

```js
if (val < 0) {
		progressBar.style.width = '0%';
	}
```
The complete code look something like:

```js
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.