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.