Page scroll progress bars
Tags: css, javascript, ux
Published: 2021-04-22 10:56:05

You must have seen this on blogs, or articles of other kinds (what's the difference again?). Basically, you are (perhaps correctly) assumed to be one of those readers who are either super-busy or super-lazy, and therefore need to know how much of the page you have visually consumed. So there's some kind of a progress bar that tells you how much you've scrolled. It looks cool, helps your readers/users, and is super simple to implement. Let's dig right in.

(If you're viewing this post on [https://debadeepsen.com/blog/page-scroll-progress-bars-fjl/](https://debadeepsen.com/blog/page-scroll-progress-bars-fjl/), you can already see this in action)

## Progress percent
Before we get into any progress bar, we need to calculate the progress percent, aka, how much of the page has been scrolled. Thanks to the helpful people at <a href="https://css-tricks.com/how-i-put-the-scroll-percentage-in-the-browser-title-bar/" target="_blank">CSS Tricks</a>, I was able to compute that easily. The following code does exactly that.

```javascript
let scrollTop = window.scrollY;
let docHeight = document.body.offsetHeight;
let winHeight = window.innerHeight;
let scrollPercent = scrollTop / (docHeight - winHeight);
let scrollPercentRounded = Math.round(scrollPercent * 100);
```

## Horizontal progress bar
This one's the simpler one of the two. All we need to do here is have a `div` "stick" to the top of the page, and set its background to display a visual indication of the progress. The trick here is to use the `linear-gradient()` CSS function, which you can read up all about <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient()" target="_blank">here</a>. Now, instead of a smooth gradient, what we need to achieve is a distinct color change at certain point. For that, we can use the "linear-color-stop" overload (somebody please check if they're still called function overloads in CSS, I honestly don't know for sure). If we give the gradient two colors, and set the progress percent as the color-stop for both, the result will be a distinct change of color. Since we'll be using JavaScript to set it, here's what that will look like:

```javascript
document.querySelector("pb").style.background = 
   `linear-gradient(to right, #498 ${scrollPercentRounded}%, #eee ${scrollPercentRounded}%)`;
```
> The greenish "progress bar" isn't overlain on top of the grey bar, but using `linear-gradient` this way gives the impression that it does.

Now if you add the JavaScript code above to the `onscroll` event handler for the page (be patient, a TL;DR CodeSandbox is at the end of this article, as usual), you should be able to see the scroll progress bar in action.

## Circular progress indicator
The circular progress bar(?!) is similar, with a little more coding effort added. We'll still be using gradients, but this time, we're going to use something called the "conic gradient". Which, as the name suggests, displays a gradient to make it appear that... um, you're staring at a cone downwards from top? (My description skills aren't astounding, so why don't you look it up on the official <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/conic-gradient()">docs</a>?) But the principle remains the same - we define "hard stops" so that the gradient looks less like a smooth gradient and more like a sharp change in color. That means setting the `background` programmatically in the following way.

```javascript
// using variables from the code block above
let scrollPercent = scrollTop / (docHeight - winHeight);
let scrollPercentRounded = Math.round(scrollPercent * 100);
let degrees = scrollPercent * 360;
        
document.querySelector(".bg").style.background = `conic-gradient(#498 ${degrees}deg, #ddd ${degrees}deg)`;
```
> By the way, a `div` with the same `height` and `width` that has its `border-radius` set to `50%` will be rendered as a perfect circle.

Now, if we implement a conic gradient on a circle, it will look like a pie chart, like this - 
![Imgur](https://i.imgur.com/MOZTzQe.png)

Now, you could keep the pie progress chart, but if you wanted, you could also overlay a circular disc on top of it using the right `position` attribute and dimensions, and it would look like so - 
![Imgur](https://i.imgur.com/j47BMq7.png)

And that's basically it. Thank you for reading through this patiently (and if you literally just jumped to this section for the full code, I don't hate you either - we're all busy). Here's the Sandbox. Happy coding!

{% codesandbox solitary-violet-y6s28 %}