Scrolling Progress Bar

Alt Text

Introduction

Today I will be creating an animated progress bar that updates the progress based on how far you scrolled into a content section. I saw this effect in action in the quick start installation guide for DesignWall.

Progress Bar Structure

There are two parts to this progress bar effect. The content and the bars. Each section of the content has an id which helps calculate the percentage. Each bar has a link to smooth scroll to that section.

<div class="content">

  <div id="intro">
    <h2>Introduction</h2>
    <p>Content</p>
  </div>
  <div id="part-1">
    <h2>Part 1: Do this thing!</h2>
    <p>Content</p>
  </div>
  <div id="part-2">
    <h2>Part 2: Do that other thing!</h2>
    <p>Content</p>
  </div>
  
</div>
<div class="progress">
  <div class="wrapper">
    <div class="bar">
      <a href="#intro">Introduction</a>
      <i class="icon-ok"></i>
      <span></span>
    </div>
    <div class="bar">
      <a href="#part-1">Part 1: Do this thing!</a>
      <i class="icon-ok"></i>
      <span></span>
    </div>
    <div class="bar">
      <a href="#part-2">Part 2: Do that other thing!</a>
      <i class="icon-ok"></i>
      <span></span>
    </div>
  </div>
</div>

CSS Styles

The progress bars are fixed positioned when you scroll down the page. The progress bars themselves have a background color and a span element that has its width animated to simulate the progress bar.

.content {
  width: 60%;
  float: left;
  margin: 45px 0;
  padding: 0 3% 0 0;
  border-right: 1px solid rgba(255,255,255,.4);
}

.progress {
  position: relative;
  float: left;
  text-align: left;
  width: 330px;
  padding: 45px 0 0 2%;
}
  .progress .wrapper {
    position: absolute;
    width: inherit;
  }
    .progress .wrapper.affix {
      position: fixed;
      top: 10px;

    }
  .progress .bar {
    position: relative;
    display: block;
    width: 100%;
    height: 40px;
    margin-bottom: 10px;
    background-color: #1c92db;
  }
  .progress .bar span {
    position: absolute;
    display: block;
    top: 0;
    width: 0;
    height: 40px;
    z-index: 0;
    background-color: #1275b7;
  }
  .progress .bar a {
    line-height: 40px;
    position: relative;
    z-index: 1;
  }
  .progress .bar i {
    position: absolute;
    right: -30px;
    height: 40px;
    line-height: 40px;
    color: #36a7f3;

    -webkit-transition: color .3s;
    transition: color .3s;
  }

jQuery

Here is where the code calculates the percentages. Using a mixture of scrollTop and offsets of the sections height.

var wrapper_top = $(".progress .wrapper").offset().top;
$(window).scroll(function (){
	var wrapper_height = $(".progress .wrapper").height();

	// Affixes Progress Bars
  var top = $(this).scrollTop();
	if (top > wrapper_top - 10) {
		$(".progress .wrapper").addClass("affix");
	}
	else {
		$(".progress .wrapper").removeClass("affix");
	}


	// Calculate each progress section
	$(".content div").each(function(i){
		var this_top = $(this).offset().top;
		var height = $(this).height();
		var this_bottom = this_top + height;
		var percent = 0;

		// Scrolled within current section
		if (top >= this_top && top <= this_bottom) {
			percent = ((top - this_top) / (height - wrapper_height)) * 100;
			if (percent >= 100) { 
				percent = 100; 
  			$(".progress .wrapper .bar:eq("+i+") i").css("color", "#fff");
			}
			else {
				$(".progress .wrapper .bar:eq("+i+") i").css("color", "#36a7f3");	  				  				
			}
		}
		else if (top > this_bottom) {
			percent = 100;
			$(".progress .wrapper .bar:eq("+i+") i").css("color", "#fff");
		}
		console.log(i);
		$(".progress .wrapper .bar:eq("+i+") span").css("width", percent + "%");
	});
});