JSFiddle - React, Tailwind, and code Playground

by Ayri Rin

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<nav>
  <div class="wrapper">
		<div class="nodes"> 
        <div class="line">
          <div class="blue">
            <div class="red-container">
              <div class="red"></div>
            </div>
          </div>
        </div>

        <div class="node">
          <div class="active-circle">
            <div class="splash"></div>
            <div class="cover">
              <div class="white"></div>
            </div>
          </div>
          <div class="inactive-circle">
            <div class="small-cover">
            </div>
          </div>
        </div>

        <div class="node">
          <div class="active-circle">
            <div class="splash"></div>
            <div class="cover">
              <div class="white"></div>
            </div>
          </div>
          <div class="inactive-circle">
            <div class="small-cover">
            </div>
          </div>
        </div>

        <div class="node">
          <div class="active-circle">
            <div class="splash"></div>
            <div class="cover">

              <div class="white"></div>
            </div>
          </div>
          <div class="inactive-circle">
            <div class="small-cover">
            </div>
          </div>
        </div>

        <div class="node">
          <div class="active-circle">
            <div class="splash"></div>
            <div class="cover">
              <div class="white"></div>
            </div>
          </div>
          <div class="inactive-circle">
            <div class="small-cover">
            </div>
          </div>
        </div>

        <div class="node">
          <div class="active-circle">
            <div class="splash"></div>
            <div class="cover">
              <div class="white"></div>
            </div>
          </div>
          <div class="inactive-circle">
            <div class="small-cover">
           ...

CSS

@import url(https://fonts.googleapis.com/css?family=Squada+One);
* {
  box-sizing: border-box;
}

body {
  background: #000;
  padding: 0px;
  margin: 0px;
}

nav {
  background: rgba(0, 0, 0, 0.8);
  padding: 18px;
  position: fixed;
  bottom: 50px;
  height: 55px;
  left: 50%;
  width: 800px;
  margin-left: -400px;
  z-index: 3;
}
nav .wrapper {
  padding: 0;
  width: 785px;
}
nav .wrapper, nav svg {
  height: 100%;
}
nav svg {
  margin-right: 15px;
  cursor: pointer;
  height: 20px;
  width: 30px;
  float: left;
}
nav svg path, nav svg rect {
  fill: #fff;
}
nav .nodes {
  position: relative;
  margin-top: -5px;
  margin-left: 5px;
  float: left;
}

.line {
  position: absolute;
  width: 705px;
  height: 1px;
  top: 14px;
}
.line .red, .line .blue {
  width: 100%;
  height: 1px;
}
.line .red-container {
  overflow: hidden;
  height: 1px;
  width: 58px;
}
.line .red {
  background-color: #4b1202;
  *zoom: 1;
  filter: progid:DXImageTransform.Microsoft.gradient(gradientType=1, startColorstr='#FF4B1202', endColorstr='#FFFD8107');
  background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuMCIgeTE9IjAuNSIgeDI9IjEuMCIgeTI9IjAuNSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZkODEwNyIvPjxzdG9wIG9mZnNldD0iMTYlIiBzdG9wLWNvbG9yPSIjZmQ4MTA3Ii8+PHN0b3Agb2Zmc2V0PSI1OCUiIHN0b3AtY29sb3I9IiNlMDNhMGQiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZDgxMDciLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2dyYWQpIiAvPjwvc3ZnPiA=');
  background-size: 100%;
  background-image: -webkit-gradient(linear, 0% 50%, 100% 50%, color-stop(0%, #fd8107), color-stop(16%, #fd8107), color-stop(58%, #e03a0d), color-stop(100%, #fd8107));
  background-image: -moz-linear-gradient(left, #fd8107 0%, #fd8107 16%, #e03a0d 58%, #fd8107...

JavaScript

$( '.links-item' ).height( window.innerHeight );
var $document = $( document.body );
var $revealBar = $( '.red-container' );
var wrapperHeight = $document.height();
var stepDistance = 101;
var documentHeight = window.innerHeight;
var positions = [];
var heights = [];
var elements = $( '.links-item:not(".main")' );

// Cache heights and positions
for( var i = 0; i < elements.length; i++ ) {
  var $element = $(elements[i]);
  var height = $element.offset().top + documentHeight;
  if (height > wrapperHeight) {
    height = wrapperHeight;
  }
  positions.push(height);
  heights.push($element.height());
}

var $nodes =  $( '.node' );

// Should totally be debounced /w animation frame. I know,
// this whole thing is slightly inefficient.
// And magic numbers too!
$( document ).scroll( function() {

  nodeTop = $document.scrollTop() + documentHeight + 1;
  var current = 0;
  
  // Active/non active states
  for( var i = 0; i < positions.length; i++ ) {
    if(nodeTop > positions[i]) {
      current = i;
      $nodes.eq( i ).addClass( 'active' );
    } else {
      $nodes.eq( i ).removeClass( 'active' );
    }
  }
  
  // Bar positioning, so sections can have different heights.
  var distanceToNext = 0;
  
  // Initial node, already has some of the bar filled.
  if( nodeTop < positions[0] ) {	
    var nextStep = (nodeTop - positions[current]) / (positions[current + 1] - positions[current]);
    
    // Calculating for node widths.
    var totalWidth = ((stepDistance) + ( current * stepDistance ) + (nextStep * stepDistance)) * 0.4;
    $revealBar.width( (0.6 * stepDistance) + totalWidth );

  // Final node covered.
  } else if (nodeTop > positions[6]) {
    $revealBar.width(stepDistance * (current + 1));
  
  // regular nodes
  } else if ( current < elements.length ) {
    var nextStep = (nodeTop - positions[current]) / (positions[current + 1] - positions[current]);
    var totalWidth = stepDistance + ( current * stepDistance ) + (nextStep * stepDistance);
	...