1
\$\begingroup\$

This week I've had an idea for an Ajax loader animation: An air bubble ascending in a glass tube.

Something like shown here: https://en.wikipedia.org/wiki/Spirit_level#/media/File:DetalleNivelDeBurbuja.jpg

I've used CSS-keyframes and -filters for to implement my idea. Finally I made a little demo for simulating the loading of data via Ajax-request.

Compiled and minified code as an Live-Demo:

"use strict";
! function() {
  function e() {
    return 1e3 * (Math.floor(28 * Math.random()) + 3)
  }

  function t() {
    var e = document.querySelectorAll(".demo");
    e.forEach(function(e) {
      var t = e.classList;
      t.contains("visible") ? (t.remove("visible"), t.add("hidden")) : (t.remove("hidden"), t.add("visible"))
    })
  }
  var n = document.querySelector(".load-data");
  n.addEventListener("click", function() {
    t(), setTimeout(t, e())
  })
}();
body {
  background-color: #7575ba
}
.ajax-loader-wrapper {
  max-width: 400px;
  margin: 60px auto;
  position: relative
}
.ajax-loader {
  max-width: 300px;
  height: 30px;
  position: relative;
  left: 50%;
  -webkit-transform-origin: left;
  transform-origin: left;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  overflow: hidden;
  border-radius: 8px;
  border: 1px solid;
  box-shadow: 3px 3px 9px #000, inset 0 3px 9px #4d4d4d
}
.ajax-loader .tube {
  background: -webkit-linear-gradient(#000, #fff, #000);
  background: linear-gradient(#000, #fff, #000);
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 1000;
  opacity: .4;
  box-shadow: 3px 0 3px #646464;
  -webkit-filter: sepia(0.6);
  filter: sepia(0.8)
}
.ajax-loader div.bubble {
  box-sizing: border-box;
  position: absolute;
  width: 10%;
  height: 100%;
  border-radius: 50%;
  border: 3px solid;
  -webkit-animation: moveBubble 3s linear infinite;
  animation: moveBubble 3s linear infinite;
  left: 20px;
  z-index: 1;
  -webkit-filter: blur(2px);
  filter: blur(2px);
  background: -webkit-linear-gradient(#646464, #c8c8c8, #fff, #c8c8c8, #646464);
  background: linear-gradient(#646464, #c8c8c8, #fff, #c8c8c8, #646464)
}
a.demo {
  color: white;
  background: -webkit-linear-gradient(#9797cb, #323264);
  background: linear-gradient(#9797cb, #323264);
  text-decoration: none;
  text-transform: uppercase;
  width: 200px;
  margin: 0 auto;
  text-align: center;
  font-size: 1.3rem;
  padding: 10px 5px;
  border: 3px solid;
  border-radius: 8px;
  font-family: Futura, "Trebuchet MS", Arial, sans-serif
}
a.demo:hover {
  opacity: .7;
  cursor: crosshair
}
a.demo:active {
  background: -webkit-linear-gradient(#323264, #9797cb);
  background: linear-gradient(#323264, #9797cb)
}
.visible {
  display: block
}
.hidden {
  display: none
}
@-webkit-keyframes moveBubble {
  from {
    left: -20%
  }
  to {
    left: 120%
  }
}
@keyframes moveBubble {
  from {
    left: -20%
  }
  to {
    left: 120%
  }
}
<div class="ajax-loader-wrapper">
  <a href="#" class="demo load-data visible">Load Ajax data</a> 
  <div class="ajax-loader demo hidden">
    <div class="tube"></div>
    <div class="bubble"></div>
  </div>
</div>

My uncompiled code (for actual codereview):

(function() {
  var loadDataButton = document.querySelector('.load-data');

  function createRandomDuration() {
    return (Math.floor(Math.random() * 28) + 3) * 1000;
  }

  function toggleHidden() {
    var demoItems = document.querySelectorAll('.demo');

    demoItems.forEach((item) => {
      var classes = item.classList;

      if (classes.contains('visible')) {
        classes.remove('visible');
        classes.add('hidden');
      } else {
        classes.remove('hidden');
        classes.add('visible');
      }
    });
  }

  loadDataButton.addEventListener('click', function() {
    toggleHidden(); // Make the animation visible. Remove the button. 
    setTimeout(toggleHidden, createRandomDuration()); // After duration: Invert everything again ...
  });
})();
$primaryBarColor: rgba(50, 50, 100, 1.0);
$borderRadius: 8px;
$bubbleGradientExtrema: rgba(100, 100, 100, 1.0);
$bubbleGradientThird: rgba(200, 200, 200, 1.0);
$bubbleGradientCenter: rgba(255, 255, 255, 1.0);

body {
  background-color: lighten($primaryBarColor, 30%);
}

.ajax-loader-wrapper {
  max-width: 400px;
  margin: 60px auto;
  position: relative;
}

.ajax-loader {
  max-width: 300px;
  height: 30px;
  position: relative;
  left: 50%;
  transform-origin: left;
  transform: translateX(-50%);
  overflow: hidden;
  border-radius: $borderRadius;
  border: 1px solid;
  box-shadow: 3px 3px 9px black, inset 0 3px 9px lighten(black, 30%);
}

.ajax-loader .tube {
  background: linear-gradient(black,white, black);
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 1000;
  opacity: .4;
  box-shadow: 3px 0 3px rgba(100, 100, 100, 1.0);
  -webkit-filter: sepia(.6);
  filter: sepia(.8);
}

.ajax-loader div.bubble {
  box-sizing: border-box;
  position: absolute;
  width: 10%;
  height: 100%;
  border-radius: 50%;
  border: 3px solid;
  animation: moveBubble 3s linear infinite;
  left: 20px;
  z-index: 1;
  -webkit-filter: blur(2px);
  filter: blur(2px);
  background:
    linear-gradient(
      $bubbleGradientExtrema,
      $bubbleGradientThird,
      $bubbleGradientCenter,
      $bubbleGradientThird,
      $bubbleGradientExtrema);
}

a.demo {
  color: white;
  background: linear-gradient(lighten($primaryBarColor, 40%), $primaryBarColor);
  text-decoration: none;
  text-transform: uppercase;
  width: 200px;
  margin: 0 auto;
  text-align: center;
  font-size: 1.3rem;
  padding: 10px 5px;
  border: 3px solid;
  border-radius: $borderRadius;
  font-family: Futura, "Trebuchet MS", Arial, sans-serif;
}

a.demo:hover {
  opacity: .7;
  cursor: crosshair;
}

a.demo:active {
  background: linear-gradient($primaryBarColor, lighten($primaryBarColor, 40%));
}

.visible {
  display: block;
}

.hidden {
  display: none;
}

@keyframes moveBubble {
  from {
    left: -20%; // -20% & 120% => For to accomplish some lack between iterations.
  }
  to {
    left: 120%;
  }
}
<div class="ajax-loader-wrapper">
  <a href="#" class="demo load-data visible">Load Ajax data</a> 
  <div class="ajax-loader demo hidden">
    <div class="tube"></div>
    <div class="bubble"></div>
  </div>
</div>

I'm sure there could be improvements.

So therefore:

Any suggestions, opinions and hints concerning corrections and/or changes welcomed.

\$\endgroup\$
  • \$\begingroup\$ From a code perspective there is not much to say, apart from maybe use const rather than var if a variable is not going to change. As for "look" that is not really something to be asking of codereview. \$\endgroup\$ – Blindman67 Dec 18 '16 at 15:36
  • \$\begingroup\$ @Blindman Thanks for you comment. I appreciate it. Have edited my question. \$\endgroup\$ – michael.zech Dec 19 '16 at 3:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.