JSFiddle - React, Tailwind, and code Playground

by rohanmod27

HTML

<nav>
  <a href="#" class="red" data-speed="4" data-color="#f33">Red</a>
  <a href="#" class="green" data-speed="4" data-color="#3f3">Green</a>
  <a href="#" class="blue" data-speed="4" data-color="#39f">Blue</a>
  <a href="#" class="yellow" data-speed="4" data-color="#ff3">Yellow</a>
</nav>

CSS

body {
  background: #1a1a1a;
  font: 100%/1.5 helvetica, arial, sans-serif;
  padding: 0 0 0 0;
}

nav {
  left: 0;
  margin: -33px 0 0 0;
  position: absolute;
  text-align: center;
  top: 50%;
  width: 100%;
}

nav a {
  background: #2c2c2c;
  border: 4px solid transparent;
  box-shadow: 0 0 0 1px #3c3c3c, 0 0 0 2px #000;
  display: inline-block;
  font-size: 18px;
  font-weight: bold;
  height: 50px;
  line-height: 50px;
  margin: 0 3px;
  padding: 0 40px;
  position: relative;
  text-decoration: none;
  text-shadow: 0 -1px 1px #111;
  transition: all 400ms;
}

nav a.red { color: #f33; }
nav a.green { color: #3f3; }
nav a.blue { color: #39f; }
nav a.yellow { color: #ff3; }

nav a canvas {
  display: block;
  opacity: 0;
  position: absolute;
}

nav a:hover {
  background: #333;
  color: #fff;
}

JavaScript

(function(){for(var d=0,a=["webkit","moz"],b=0;b<a.length&&!window.requestAnimationFrame;++b)window.requestAnimationFrame=window[a[b]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[a[b]+"CancelAnimationFrame"]||window[a[b]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(b){var a=(new Date).getTime(),c=Math.max(0,16-(a-d)),e=window.setTimeout(function(){b(a+c)},c);d=a+c;return e});window.cancelAnimationFrame||(window.cancelAnimationFrame=
function(a){clearTimeout(a)})})();

var $elems = $('nav a');

function Border( opt ){
  this.elem = opt.elem;
  this.active = false;
  this.canvas = document.createElement('canvas');
  this.ctx = this.canvas.getContext('2d');
  this.width = this.canvas.width = this.elem.outerWidth();
  this.height = this.canvas.height = this.elem.outerHeight();
  this.borderSize = parseInt(this.elem.css('border-left-width'), 10);
  this.waypoints = [
    [0, 0],
    [this.width - this.borderSize, 0],
    [this.width - this.borderSize, this.height - this.borderSize],
    [0, this.height - this.borderSize]
  ];
  this.tracer = {
    x: 0,
    y: 0,
    color: opt.color,
    speed: opt.speed,
    waypoint: 0
  };
  this.canvas.style.top = -this.borderSize + 'px';
  this.canvas.style.left = -this.borderSize + 'px';
  this.elem.append($(this.canvas));
}

Border.prototype.loop = function(){
  if(this.active){
    requestAnimationFrame($.proxy(this.loop, this));   
    this.ctx.globalCompositeOperation = 'destination-out';
    this.ctx.fillStyle = 'rgba(0, 0, 0, .05)';
    this.ctx.fillRect(0, 0, this.width, this.height);
    this.ctx.globalCompositeOperation = 'source-over';
    this.ctx.fillStyle = this.tracer.color;
    this.ctx.fillRect(this.tracer.x, this.tracer.y, this.borderSize, this.borderSize);
  
    var previousWaypoint = (this.tracer.waypoint == 0) ? this.waypoints[this.waypoints.length - 1] : this.waypoints[this.tracer.waypoint - 1],
        dxTotal = previousWaypoint[0] -...