Google's iOS Gmail loading animation
Google's iOS Gmail folding loading animation using CSS transitions & JS
author(s):
Regis Gaughan, III
HTML
<!-- can be any element w/ a single child -->
<span class="gloader"><span></span></span>
CSS
.gloader {
display:inline-block; position:relative;
width:50px; height:50px; margin:10px;
font-size:0px;
}
.gloader:before,
.gloader:after,
.gloader > * {
content:' '; display:block; width:50%; height:100%;
position:absolute; top:0px; left:0px; z-index:1;
background:#21aa29; border-radius:25px 0px 0px 25px;
}
.gloader:after {
left:auto; right:0px;
background:#21aa29; border-radius:0px 25px 25px 0px;
}
.gloader > * {
position:absolute; top:0px; left:auto; right:0px; z-index:3;
background:#21aa29; border-radius:0px 25px 25px 0px;
-webkit-transform-style:preserve-3d;
-webkit-transform-origin:0px 50%;
-webkit-transition:all 0.33s 0s linear;
}
/* Generic Timing */
.gloader[data-state] > *,
.gloader[data-state$=".5"] > *{
z-index:10;
-webkit-transition-duration:0.0000001s;
-webkit-transition-timing-function:linear;
-webkit-transform:rotateY(0deg);
}
.gloader[data-state$=".5"] > * {
-webkit-transform:rotateY(-90deg);
}
.gloader[data-state$=".25"] > *,
.gloader[data-state$=".75"] > * {
z-index:11;
-webkit-transition-duration:0.33s;
-webkit-transition-timing-function:ease-in;
-webkit-transform:rotateY(-90deg);
}
.gloader[data-state$=".75"] > * {
-webkit-transition-timing-function:ease-out;
-webkit-transform:rotateY(-180deg);
}
/* Rotation - not animated */
.gloader[data-state^="0"],
.gloader[data-state^="2"] {
-webkit-transform:rotate(0deg);
}
.gloader[data-state^="1"],
.gloader[data-state^="3"] {
-webkit-transform:rotate(-90deg);
}
/*
Google Colors (Green -> Blue -> Red -> Yellow...):
Green: #21aa29 / #105514
Blue: #2159d6 / #102c6b
Red: #d62408 / #6b1204
Yellow: #ffcf00 / #7f6700
*/
/* Green -> Blue */
.gloader[data-state="0.75"] > *,
.gloader[data-state^="0"]:after {
background:#2159d6; /* Final */
}
.gloader[data-state="0"] > *,
.gloader[data-state^="0"]:before,
.gloader[data-state="0"]:after {
background:#21aa29; /* Start */
}
.gloader[data-state="0.25"] > * {
background:#105514; /* Start...
JavaScript
// Look for uninitialized gloader elements and start them up
function gloader(){
var els, i, l;
els = document.querySelectorAll('.gloader');
for(var i = 0, l = els.length; i < l; i++){
if(els[i].getAttribute('data-state') == null){
(function(el){
function inc(el){
var state = parseFloat(el.getAttribute('data-state'), 10)+.25;
if(state === 4){ state = 0; }
el.setAttribute('data-state', state);
};
el.addEventListener('webkitTransitionEnd', function(e){
// Because we're changing many different properties
// we need a constant property to check against.
// Arbitrarily chose z-index
if(e.propertyName === 'z-index'){ inc(el); }
}, false);
el.setAttribute('data-state', 0);
inc(el);
})(els[i]);
}
}
};
window.addEventListener('load', gloader);