As I test out code changes in my local environment, I always run through this interstitial/waiting page that contains a loading animation. This animation is generally done via an animated .gif, or a .swf movie. Today while waiting for my app to load some backend stuff, it occurred to me that I could pretty easily replicate this same thing in pure HTML + CSS, thus making changes to color or shape super simple.
Here's a screenshot of what I'll be replicating:

NOTE: I'm doing this assuming Chrome browser, and so will be leaning heavily on CSS3, and the -webkit- prefix. At the end of this post, there's a link to site that does a bunch of awesome automated stuff for all this, so I'm eliminating all the complexity for the sake of this talk.
Update: Just added some -moz- support too, though Firefox doesn't animate as nicely as Chrome.
HTML
First, the markup. I figure I'm looking at a div that contains 5 objects. I'm going to call this thing "loader", and each object will just be a span (because they're inline) with a class of "frame" (though I probably don't need a class on these, I wanted to add them for clarity).
So, our HTML markup will look like this:
CSS
Basic Stuff
Let's now add in some basic styling for this thing. I really don't need to do anything with my #loader container, though I certainly could add some margin offsets or whatever I want. But my frames do need some love. I'm starting by defining a light grey background:
.frame {
background: #999;
}
I'm going to set these to display: inline-block, because I want them still inline like spans want to be naturally, but also want them to have the dimension properties of block. I also want to set the size of these to 20px square, and add a right margin to offset them from one another:
.frame {
background: #999;
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10px;
}
That should get us looking like so:

.frame {
background: #999;
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10px;
border-radius: 10px;
opacity: .3;
}

Animation
Alright, now comes the really fun stuff. First, some additional reading as a point of reference: W3Schools.com: CSS3 Animations.
I need to define a name for my animation (sort of like a javascript function; I'll call ours "loader"), a duration for my animation (in this case I want my animation to last one second), and how many times I want this thing to repeat (in our case, I want it to repeat forever):
.frame {
background: #999;
display: inline-block;
width: 20px;
height: 20px;
margin-right: 10px;
opacity: .3;
border-radius: 10px;
-webkit-animation-name: loader;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
}
Nothing is going to happen yet though because we need to define what, specifically our animation is supposed to DO. Essentially, I want these circles to:
- Fade in/out
- Change color
- Grow slightly
@-webkit-keyframes loader {
0% {}
50% {}
100% {}
}
Now that we have our keyframes for our animation defined, we can define WHAT we want to happen at 0%, 50%, and 100% of our animation. Recalling my list of things I want to do (fade in/out, color change, size change), I'll add those in my keyframes. Note I don't need to define every property of my starting and ending points, because that's handled with our .frame styles we defined earlier. As such, I just need to define how these look in the middle of the animation, in this case opacity of 1, background-color of red, and I want to scale them up just a touch:
@-webkit-keyframes loader {
0% { }
50% { opacity: 1.0;
background-color:red;
-webkit-transform: scale(1.2); }
100% { }
}
Now We have a nice set of circles that all sort of pulse together from slightly transparent light grey to a full opaque and slightly larger red. But we want each of these to sort of follow each other in the animation; that is, we don't want all of them pulsing simultaneously, but rather independently, and one right after the other. I can do this using nth-child selection and a keyframe animation delay for each of my 5 .frame objects. Because my animation is 1 second long, and I have 5 objects, I'll just divide 1/5 and set each animation delay to offset by .2 seconds; that CSS will look like this:
.frame:nth-child(1) {
-webkit-animation-delay:0.2s;
}
.frame:nth-child(2) {
-webkit-animation-delay:0.4s;
}
.frame:nth-child(3) {
-webkit-animation-delay:0.6s;
}
.frame:nth-child(4) {
-webkit-animation-delay:0.8s;
}
.frame:nth-child(5) {
-webkit-animation-delay:1s;
}
Sweeeeeet. Now we're cooking with fire! So, what I've done is just delayed when the animation is supposed to start for each of my .frame objects, and presto - we've replicated our loader.
Changing color or shape
Before, my loading page used either an animated .gif/.swf, which if I wanted to change the color of these circles means I'd have to have extra software, or at the very least spend a little time re-working my graphics so I can output the new file. But now, if we wanted to change this to say, blue and square, all we need to do is edit some CSS:
.frame {
border-radius: 0;
}
@-webkit-keyframes loader {
50% { opacity: 1.0;
background-color:blue;
-webkit-transform: scale(1.2); }
}
Demo
The above demo won't animate unless you're using a Mozilla or Webkit browser
Demo with Full Code (Demo currently works only in Webkit or Mozilla browsers)
Death to browser prefixes!!!
ReplyDeleteYes, but we're not there yet: http://caniuse.com/#feat=css-animation. The W3C Working Group hasn't finalized these specifications yet, which means we are forced to either use prefixed implementations, or not use these features at all. Up to you how you want to move forward.
ReplyDeleteThanks for reading!