Chances are you have already ran into sites where there is a bar, usually located in the header, that increase or decrease according to the page scroll. So, that's what this post is about.
🔍 Overview
Basically, what we want to do is to check where is the scroll compared to page content size, so if the user have scrolled until the middle of the content, the bar is supposed to fulfill 50%, and so on, always tracking and applying the math to do so.
HTML
After fitting the bar in the HTML body, just like the codepen example above, add some content to be able to see some effect when scrolls happen.
<div class='scroll-bar-wrapper'>
<div class='scroll-bar'> </div>
</div>
JavaScript
window.addEventListener('scroll',()=> indicateScrollBar())
function indicateScrollBar() {
const distanceFromPageTop = document.body.scrollTop || document.documentElement.scrollTop;
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrolled = (distanceFromPageTop / height) * 100;
document.querySelector(".scroll-bar").style.width = `${scrolled}%`;
}
- In .js file,
window.addEventListener('scroll',()=> indicateScrollBar())
tells that whenever the user happens to scroll down or up in the window,indicateScrollBar()
is called. In this function, we first encounter
distanceFromPageTop
, a variable that will receive eitherdocument.body.scrollTop
ordocument.documentElement.scrollTop
. If the first does not exist or the browser doesn't recognize, or it's falsy, the second is reserved to that variable, so explained by the||
(Logical OR) in the middle of them. Almost all browsers consider the first one, a property that give us a number meaning how far in pixels we are from the top.document.body.scrollTop
differs fromdocument.documentElement.scrollTop
just because the latter deals with the whole HTML document, and the first deals with the body itself. In this case, it doesn't affect which is used.Another variable, so, is declared:
height
. This one will receive the result ofdocument.documentElement.scrollHeight - document.documentElement.clientHeight
. But what does exactly this expression mean?
document.documentElement.scrollHeight
gives us a number referring to the height of HTML document, the max number that we can get until the scroll stuck in the bottom, the whole content.
document.documentElement.clientHeight
gives us a number referring to the height of HTML document that we can see, that's viewable.
scrolled
is another variable that received the expression(distanceFromPageTop / height) * 100
which will give us the final number.Lastly, we get the bar via DOM, and applies this final number as the width of the bar, not forgetting to add the % signal.
Illustration of the difference between clientHeight
and scrollHeight
CSS
.scroll-bar-wrapper {
width: 100%;
height:10px;
position:fixed;
top:0;
left:0;
background:#CCCCCC;
}
.scroll-bar {
width:0;
height: inherit;
background: #8D7ECA;
}
Now in .css file, we style the bar. The bar wrapper covers 100% of the screen, also fixed at the top, so even in the scrolls it appears. Moreover, the .scroll-bar
, the visual bar in itself, receive initially width:0
, as it will change with the user scrolls. As well, the same height as the wrapper, its father, and the color to make it all visual.
You can make lots of different styles. This is just a sample with the essence. For instance, you could make the bar as a pseudo-element of main
, so avoiding HTML directly, just like so:
✔️ Windup
I wish you found it interesting or learn sth. Goodbye! 👋
Top comments (7)
Hi Leonardo,
I wrote about the same topic a while ago.
Make a Reading Progress Bar for your Blog 📊
Rob OLeary ・ Apr 21 '20 ・ 5 min read
I chose to use
<progress>
rather than<div>
. It is better for accessibility, but requires more effort to style.I discussed optimization using
requestAnimation
and debouncing also.I would consider doing both of these if you are putting this into a live website.
All the best
Nice article. I have one suggestion. Do your DOM write inside a
requestAnimationFrame
callback.I took this explanation from some code I wrote a while ago:
Good post!
I wondered if this could be done without adding elements to the HTML, here is my slightly modified version: codepen.io/Korbraan/pen/bGgGPbO :)
That's awesome! In fact, not adding elements to the HTML might be better... thanks for pointing out, I'm going to comment it in the post soon :)
Nice article, Thank you
Amazing article. neatly explained
you are kind