When loading content in via ajax web browsers do not usually give clear indication they are fetching additional content. This is typically found with endless scrolling sites, however the latest UI trend as seen on Medium and Youtube is a top animated loading bar when fetching additional content. Here is a screenshot of the medium example:
So how do they do it?
Well lets start with some basic HTML/CSS. When using developer tools in chrome on the page I noticed that they kept adding a class to the body tag:
app-loadingSo I added the class manually and the loading bar showed up and stayed put.Still using developer tools I found the div that made up the loading bar down at the bottom of the html right above the closing script tags. here is the HTML that makes up the loading bar:
<div class="loading-bar"></div>Super simple so far, now the CSS, by default the style applied is:
.loading-bar { position: fixed; display: none; top: 0; left: 0; right: 0; height: 2px; z-index: 800; background: #60d778; -webkit-transform: translateX(100%); -moz-transform: translateX(100%); -o-transform: translateX(100%); transform: translateX(100%); }Notice the display: none; This hides the bar from view initially. When we continue to look through the CSS we see that app-loading class overrides this default display: none.
.app-loading .loading-bar { display: block; -webkit-animation: shift-rightwards 1s ease-in-out infinite; -moz-animation: shift-rightwards 1s ease-in-out infinite; -ms-animation: shift-rightwards 1s ease-in-out infinite; -o-animation: shift-rightwards 1s ease-in-out infinite; animation: shift-rightwards 1s ease-in-out infinite; -webkit-animation-delay: .4s; -moz-animation-delay: .4s; -o-animation-delay: .4s; animation-delay: .4s; }So by adding the app-loading class to the body while loading content into the page, you effectively get an animated loading bar fixed to the top of the page.
Last code sample is the CSS3 animation we “hijacked” from Medium, they called it: shift-rightwards, so lets give that developer credit and keep the name in the demo.
@-webkit-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @-moz-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @-o-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } }Easy enough, so how can we apply this to our own websites?
- Just before making an ajax request add the class app-loading to the < body / > tag.
- After the ajax has finished (make sure also to catch on timeout or error) remove the class from the body tag.
Full Working Example using jQuery:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Loading Bar Sample</title> <style> .app-loading .loading-bar { display: block; -webkit-animation: shift-rightwards 1s ease-in-out infinite; -moz-animation: shift-rightwards 1s ease-in-out infinite; -ms-animation: shift-rightwards 1s ease-in-out infinite; -o-animation: shift-rightwards 1s ease-in-out infinite; animation: shift-rightwards 1s ease-in-out infinite; -webkit-animation-delay: .4s; -moz-animation-delay: .4s; -o-animation-delay: .4s; animation-delay: .4s; } .loading-bar { position: fixed; display: none; top: 0; left: 0; right: 0; height: 2px; z-index: 800; background: #60d778; -webkit-transform: translateX(100%); -moz-transform: translateX(100%); -o-transform: translateX(100%); transform: translateX(100%); } @-webkit-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @-moz-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @-o-keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } @keyframes shift-rightwards { 0% { -webkit-transform:translateX(-100%); -moz-transform:translateX(-100%); -o-transform:translateX(-100%); transform:translateX(-100%); } 40% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 60% { -webkit-transform:translateX(0%); -moz-transform:translateX(0%); -o-transform:translateX(0%); transform:translateX(0%); } 100% { -webkit-transform:translateX(100%); -moz-transform:translateX(100%); -o-transform:translateX(100%); transform:translateX(100%); } } </style> </head> <body> <div>random content here</div> <div class="loading-bar"></div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script> $(function() { $("body").addClass("app-loading"); $.get("some-test-page.html", function(data) { $("body").removeClass("app-loading"); }); }) </script> </body> </html>