Sticky Reading Progress Nav Bar With Smooth Scroll Support
| File Size: | 4.82 KB |
|---|---|
| Views Total: | 3850 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
A fancy responsive sticky reading progress bar to indicate how much of the main content has been read based on a user's scroll position. Written in jQuery JavaScript library.
By default, the script walks through your heading elements (h2) and generates a sectioned progress bar that auto updates as you scroll down the webpage.
Also can be used as a sticky navigation bar that allows the user to scroll between content sections by clicking on the nodes inside the reading progress bar.
How to use it:
1. Create sectioned content separated with <h2> tag as these:
<h2>Section One</h2> <p>Section 1 Content</p> <h2>Section Two</h2> <p>Section 2 Content</p> <h2>Section Three</h2> <p>Section 3 Content</p> ...
2. The main JavaScript (jQuery script) to create a reading progress bar and make it sticky on the top of the webpage on scroll. Copy and add the followng JS snippets after jQuery.
// set up and create progress bar in DOM
$('h2').eq(0).before('<div class="progressbar"></div>');
var container = $('.progressbar');
container.append('<div class="shim"></div>');
var shim = $('.progressbar .shim');
container.append('<div class="holder clearfix"></div>');
var holder = $('.progressbar .holder');
holder.append('<div class="bar"></div>');
var bar = $('.progressbar .bar');
bar.append('<div class="indicator"></div>');
var indicator = $('.progressbar .indicator');
holder.append('<div class="labels"></div>');
var labels = $('.progressbar .labels');
$('h2').each(function(){
var code = '<i data-label="'+$(this).text()+'"></i>';
labels.append(code);
});
var points = labels.find('i');
points.css('width', 100/$('h2').length+'%');
// match height of shim
// stop layout jumping when progress bar fixes to / unfixes
// from top of viewport
function setShimHeight(){
shim.css('height', container.height()+'px');
}
setShimHeight();
$(window).resize(function(){ setShimHeight(); });
// position indicator bar so it starts at first dot
function setIndicatorX(){
var point = points.eq(0);
var xpos = point.offset().left + (point.width() / 2);
indicator.css('left', xpos+'px');
}
setIndicatorX();
$(window).resize(function(){ setIndicatorX(); });
// fix/unfix progress bar to top of viewport
function fixPosition(){
if(container.is(':visible')) {
if(!container.hasClass('fixed')) {
if(holder.offset().top <= $(window).scrollTop()) {
container.addClass('fixed');
}
}
else {
if(shim.offset().top > $(window).scrollTop()) {
container.removeClass('fixed');
}
}
}
}
fixPosition();
$(window).scroll(function(){ fixPosition() });
$(window).resize(function(){ fixPosition(); });
// set trigger point
// i.e. how far down viewport is the "eye line"
var triggerPoint = 0;
function setTriggerPoint(){
triggerPoint = $(window).height() * .18;
}
setTriggerPoint();
$(window).resize(function(){ setTriggerPoint(); });
// update progress bar
function setPosition(){
if(container.is(':visible')) {
var section = false;
var sectionIndex = 0;
var currentPosition = $(window).scrollTop() + triggerPoint;
// dots
// if before first section
if(currentPosition < $('h2').eq(0).offset().top) {
points.removeClass('reading read');
section = -1;
}
// if after first section
else {
$('h2').each(function(){
var sectionTop = $(this).offset().top;
if(currentPosition >= sectionTop) {
points.removeClass('reading');
points.eq(sectionIndex).addClass('reading');
points.eq(sectionIndex).addClass('read');
section = sectionIndex;
}
else {
points.eq(sectionIndex).removeClass('read');
}
sectionIndex++;
});
}
// bar
var barWidth = 0;
// if before start
if(section == -1) {
var point = points.eq(0);
barWidth = point.offset().left + (point.width() / 2);
}
// if after end
else if(section >= (points.length - 1)) {
var point = points.eq((points.length - 1));
barWidth = point.offset().left + (point.width() / 2);
}
// if within document
else {
var startPoint = points.eq(section);
var startPointX = startPoint.offset().left;
var startPointWidth = startPoint.width();
var startSection = $('h2').eq(section);
var endSection = $('h2').eq(section+1);
var startSectionY = startSection.offset().top;
var endSectionY = endSection.offset().top;
var sectionLength = endSectionY - startSectionY;
var scrollY = currentPosition - startSectionY;
var sectionProgress = scrollY / sectionLength;
barWidth = startPointX + (startPointWidth / 2) + (startPointWidth * sectionProgress);
}
barWidth -= indicator.offset().left;
indicator.css('width', barWidth+'px');
}
}
setPosition();
$(window).scroll(function(){ setPosition(); });
$(window).resize(function(){ setPosition(); });
3. The JavaScript to activate the smooth scroll functionality.
points.click(function(){
var sectionIndex = points.index($(this));
var targetY = $('h2').eq(sectionIndex).offset().top - (triggerPoint * .92);
$('html, body').animate({scrollTop:targetY}, 600);
});
4. The generated HTML of the reading progress bar should be like this:
<div class="progressbar fixed">
<div class="shim" style="height: 85.6563px;"></div>
<div class="holder clearfix">
<div class="bar">
<div class="indicator" style="left: 112.133px; width: 358.257px;"></div>
</div>
<div class="labels">
<i data-label="Section One" style="width: 16.6667%;" class="read"></i>
<i data-label="Section Two" style="width: 16.6667%;" class="read"></i>
<i data-label="Section Three" style="width: 16.6667%;" class="read reading"></i>
<i data-label="Section Four" style="width: 16.6667%;"></i>
<i data-label="Section Five" style="width: 16.6667%;"></i>
<i data-label="Section Six" style="width: 16.6667%;"></i></div>
</div>
</div>
5. Style the reading progress bar using the following CSS snippets.
.progressbar {
display: none;
margin: 4em 0;
}
@media only screen and (min-width: 650px) {
.progressbar { display: block; }
}
.progressbar .shim {
display: none;
width: 100%;
}
.progressbar .holder {
position: relative;
font-size: 85%;
padding: 1.8em 0 0 0;
background-color: #D6E1E5;
box-shadow: 0 0.5em 1.5em #D6E1E5;
}
@media only screen and (min-width: 750px) {
.progressbar .holder { font-size: 90%; }
}
@media only screen and (min-width: 900px) {
.progressbar .holder { font-size: 95%; }
}
.progressbar .holder .bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background-color: #B6D1DA;
}
.progressbar .holder .bar .indicator {
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: #4598B5;
}
.progressbar .holder .labels {
max-width: 1280px;
margin: 0 auto;
padding: 0 2em;
text-align: center;
}
.progressbar .holder .labels i {
display: block;
position: relative;
float: left;
cursor: pointer;
}
.progressbar .holder .labels i::before {
position: absolute;
bottom: 0;
left: 50%;
display: block;
content: '';
width: .9em;
height: .9em;
border-radius: 50%;
border: solid 3px #B6D1DA;
background-color: #D6E1E5;
-webkit-transform: translateX(-50%) translateY(50%);
transform: translateX(-50%) translateY(50%);
transition: border-color 100ms ease-in, background-color 150ms ease-in;
}
.progressbar .holder .labels i::after {
display: block;
content: attr(data-label);
position: relative;
top: 0;
padding-bottom: 1.8em;
font-family: 'Open Sans';
font-weight: 400;
color: #4598B5;
transition: color 150ms ease-in, top 100ms ease-out;
}
.progressbar .holder .labels i:hover::before, .progressbar .holder .labels i:focus::before { background-color: #B6D1DA; }
.progressbar .holder .labels i:hover::after, .progressbar .holder .labels i:focus::after { top: -.2em; }
.progressbar .holder .labels i.read::before { border-color: #4598B5; }
.progressbar .holder .labels i.read:hover::before, .progressbar .holder .labels i.read:focus::before { background-color: #4598B5; }
.progressbar .holder .labels i.reading::after { color: #222; }
.progressbar .holder .labels i.reading:hover::after, .progressbar .holder .labels i.reading:focus::after { top: 0; }
.progressbar.fixed .holder {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1;
}
.progressbar.fixed .shim { display: block; }
This awesome jQuery plugin is developed by Ed Hicks. For more Advanced Usages, please check the demo page or visit the official website.





