A progress bar only at the top of the page is boring. Really boring. Everyone does it because progress
is already a native HTML element. I wanted to build something that was made specifically for longer pages with a lot of content. I also wanted to add some style to the page where the content is being framed as you scroll. So I built a wraparound progress bar.
The Setup
<div class="progress-top"></div>
<div class="progress-right"></div>
<div class="progress-bottom"></div>
<div class="progress-left"></div>
$color-progress: #ffc769;
$progress: 0.35em;
.progress-top,
.progress-right,
.progress-bottom,
.progress-left {
position: fixed;
z-index: 999;
background-color: $color-progress;
}
.progress-top,
.progress-bottom {
height: $progress;
}
.progress-right,
.progress-left {
width: $progress;
}
.progress-top,
.progress-right {
top: 0;
}
.progress-top,
.progress-left {
left: 0;
}
.progress-bottom,
.progress-left {
bottom: 0;
}
.progress-bottom,
.progress-right {
right: 0;
}
The Script
const ProgressScroll = (() => {
let s;
return {
settings() {
return {
top: $('.progress-top'),
right: $('.progress-right'),
bottom: $('.progress-bottom'),
left: $('.progress-left'),
windowHeight: $(window).height(),
windowWidth: $(window).width(),
scrollHeight: $(document).height() - $(window).height(),
progressTotal: $(window).height() * 2 + $(window).width() * 2,
scrollPosition: $(document).scrollTop()
};
},
init() {
s = this.settings();
this.bindEvents();
},
bindEvents() {
$(window).on('scroll', this.onScroll);
$(window).on('resize', this.onResize);
this.progress();
},
onScroll() {
s.scrollPosition = $(document).scrollTop();
ProgressScroll.requestTick();
},
onResize() {
s.windowHeight = $(window).height();
s.windowWidth = $(window).width();
s.scrollHeight = $(document).height() - s.windowHeight;
s.progressTotal = s.windowHeight * 2 + s.windowWidth * 2;
ProgressScroll.requestTick();
},
requestTick() {
requestAnimationFrame(this.progress);
},
progress() {
const percentage = s.scrollPosition / s.scrollHeight;
const width = s.windowWidth / s.progressTotal;
const height = s.windowHeight / s.progressTotal;
s.top.css('width', `${(percentage / width) * 100}%`);
s.right.css('height', `${((percentage - width) / height) * 100}%`);
s.bottom.css('width', `${((percentage - width - height) / width) * 100}%`);
s.left.css('height', `${((percentage - width - height - width) / height) * 100}%`);
}
};
})();
ProgressScroll.init();
I know. It uses jQuery. I originally wrote the script in vanilla JavaScript, but the styling would not always reach 100% for each div
depending on the scroll speed. This would sometimes leave gaps in between the progress bar since it really is four separate elements.