Regis Gaughan, III

Google’s 3D Loading Animation

DON’T READ THIS. While this attempt was great at the time, there’s a much more improved method I’ve written up over here: Google/Gmail’s 3D Loader. Enjoy.

The new Google loading animation is pretty neat. I wanted to see if I could recreate it using only CSS. Unfortunately, I needed the help of JavaScript to trigger the changes between “keyframes” but, in the end, I got it fully recreated.

If you’re on Chrome you should see the 3D-Page-Flipping-Color-Changing-Circle-Animation Google uses when Gmail and Chrome are loading content, at least on iOS. The animation should work with other 3D-transition supported browsers, but I only built it for Chrome at the moment. Feel free to modify the CSS and event names to get it more cross-browser.

Want to jump right in? View the Gist or View the jsFiddle right now.

“Okay fancy-pants, how’s you do that?”

Good question! The loader is constructed of two semi-circles built from :before and :after pseudo-element blocks absolutely positioned at the left and right half of the square element. there is a single child element, also a semi-circle, starting absolutely position on top of the right pseudo-element semi-circle. Only that child element is animated as a 3D fold from the right to the left. Before the fold occurs, the left pseudo-element and the child semi-circle are the same color, while the right pseudo-element that is under the child is set to the next color. As we flip the child from right to left, we darken it’s initial color up to the midway point for a 3D effect. Once it meets the midway point where it will not be visible with a width of 0, we immediately change it’s color to a slightly darker version of the next color (which is now fully seen in the right pseudo-element that used to be under the child). Now, we animate the the rest of the flip, so the child semi-circle will now be covering the left pseudo-element and the entire circle is now the next color. We then reset the positions and set the colors getting ready for the next color, as well as rotate 90 degrees so the flip occurs vertically.

All of the animation is done using CSS transitions. However, we do need JavaScript to change an attribute of the loader element when each step of the animation described above completes in order to trigger the next.

“But wait, why not use CSS Animations and drop the JavaScript?”

Ah yes, that would be great. Unfortunately, while it can be built using only CSS animations, the timing cannot be guarenteed. There are essentially three animations occuring: 1. The folding and color change of the child 2. The rotation of the parent element after each fold of the child 3. The color change of the pseudo elements at each half of the child’s fold

Because these have to be three separate CSS animations, we cannot guarantee that they will match up (in fact, they almost never do) resulting in some awful flickering. Further, we cannot animate pseudo elements at this time (though, I believe Mozilla can at the time of this writing). Therefore, we use CSS transitions with a JavaScript listener for the end of each transition to trigger the state of the element through a data-state attribute. We use data-state and CSS3 attribute selectors to reuse transitions based on part of the attributes value.

“Alright, alright… Show me the code!”

The HTML is pretty simple:

The CSS does the bulk of the work. You can see we use the attribute selector to generically match the data-state attribute. For instance, the CSS rule .gloader[data-state$=".5"] matches any “.5″ state, regardless of it is state “0.5” or “3.5”. We use .gloader[data-state^="2"] the same way, to match states “2.0” to “2.75.”

The JavaScript simply listens to the transition end event of the loader element and increments the state by a “.25″ to continue the animation. The one thing to pay attention to is we arbitrarily chose z-index to listen to. Because we’re changing several properties at different times, we can’t just increment whenever a transition ends but, rather, we need a specific property to check so we can better control when to increment the steps in inc(). If you look at the CSS, we are changing the z-index as well as the colors and transforms.

Hopefully you found that cool and could follow along. Check out the Gist on Github or the jsFiddle Demo.