CSS3 Storytelling

Be prepared to reinvent yourself. Be prepared to go out on a limb occasionally, and be prepared to do the things that you feel strongly about that maybe other people don’t….

Hillman Curtis

Prelude: Setting The Scene

There are many CSS3 animation examples scattered throughout the web. We’ve seen them. Image hover effects. Rotating solar systems. Even a pure CSS3 AT-AT Walker.

But these techniques, while useful, represent only the beginning. They’re just meant to give us a common vocabulary of CSS3 animation skills. Most are simple experiments; few are useful, finished products.

We developers are used to styling text and layout. Like photographs, these things don’t move much. But most of us aren’t used to creating full-fledged animations without the use of proprietary programs like Adobe Flash. So yes, those introductory tutorials are valuable to start us thinking in a new direction. But we need to remember that’s all they are: A start. Now it’s time to move beyond the basics. We’ve really only scratched the surface of what CSS3 animations are capable of. As an industry, I think we’re ready for a new challenge, so let’s look at how to take those basic techniques we’ve learned and tie them together into useful, finished products.

In the following example, we’re no longer developing what we think of as a static web page. We’re not worrying about Responsive Web Design or Mobile First or Content Strategy or any approach other than our own.

The first thing we must do to take advantage of this kind of CSS3 animation is alter our thinking and approach. Imagine that instead of taking photographs, we’re creating an animated movie. We are the directors. Actors are notoriously temperamental, so it’s important to remember throughout this production who’s in charge: We are. We gather our actors (HTML5 and images), tell them where to go and when (using CSS3), tell them how to behave (using JavaScript) on a stage (the web browser), and then tie it all together with a soundtrack to create a compelling animated story. You’ll recognize HTML5, CSS3, JavaScript, images, and sound as building blocks of the web. Remember: We’re dealing with web standards, not proprietary solutions. To understand how this works, let’s walk through it step by step. You’ll find it helpful to download this demo and follow along in a WebKit-based browser like Safari or Chrome with your sound on.

Interlude: A Note About Browsers

Let me get this out of the way: Throughout the following example, you’ll see I only used the -webkit vendor-specific prefix in the styles. This real-world animation was developed specifically for a well-known company’s sales & marketing team to use on their iPads. Despite this, you could easily add vendor-specific prefixes to support whatever experimental CSS3 style you need to use in your project.

Without further delay, let’s get started.

First Act: The Markup

Meet your new best friend, Royal Slider. This touch-enabled image gallery and content slider is the easiest way to get our friends HTML5, CSS3, JavaScript, images, and audio to start acting like they have the starring role in our animated movie. Developed by Dmitry Semenov, Royal Slider saved me days of work. Without it, this project would have taken much longer and been much more painful. I like the Slider with Animated Blocks template and you’ll see that’s what I based the rest of the code I’m about to show you on.

For this example, we need to think of each element in the Document Object Model as a character in our animated movie. Think of the DOM as a way to visualize the hierarchy of everything in our markup. (If you need to brush up on the concept of the DOM, read this excellent World Wide Web Consortium article.) Every bit of text, every image, every object that makes up the DOM, is capable of being instructed by CSS3 and JavaScript to appear and act a certain way at a certain time.

My animation contains 29 scenes, represented by the 29 individual DIVs in the code below. Yours may have more or less scenes. I’m showing only the first three below, but here you can see the full markup. After the wrapper DIV, we’ll see each of those interior DIVs contains a caption inside of a P and an image. You’ll also notice each DIV is consecutively named slide1, slide2, etc. This is pretty simple stuff that we should all be comfortable with so far.

<div id="slider-with-blocks-1" class="royalSlider">
  <div class="slide1">
    <p>Meet Alex.</p>
    <img src="_img/animationMeet.jpg" alt="Meet Alex." class="kenBurnsIn">
  <div class="slide2">
    <p>He developed a need.</p>
    <img src="_img/animationDeveloped.jpg" alt="He developed a need." class="kenBurnsOut">
  <div class="slide3">
    <p>Luckily for Alex this isn't a disaster.</p>
    <img src="_img/animationDisaster.jpg" alt="Luckily for Alex this isn't a disaster." class="kenBurnsIn">

Note: One could argue, as designer Andy Clarke did when explaining the wonderfully advanced Madmanimation, that rather than a DIV with multiple DIVs inside it, an OL with multiple LIs inside it might be more semantically appropriate, since each scene appears in a sequence. Whatever you choose, make it meaningful and consistent.

Second Act: The Behavior

Typically after handcrafting our markup we add style. CSS3 rocks, but sometimes it needs a hand from its friend JavaScript. This time we’re going straight to our JavaScript to set our captions and images into motion. Here’s how: Rather than having the contents of each DIV appear all at once like we often do, we’re going to use Royal Slider to have only the contents of only one DIV appear at a time. We’ll use Royal Slider’s built-in JavaScript and CSS3 components to smoothly transition between displaying each DIV in sequence.

This is where Royal Slider comes in really handy. Sure, you could spend days developing your own scripts to handle transitioning from the contents of one DIV to another, but I found Royal Slider works so well already I didn’t need to waste development cycles rewriting something that already works.

Check out the contents of Royal Slider’s jquery.rs.autoplay.js file in the demo. Built with the jQuery framework in mind, this file alone justified the $12 cost of Royal Slider for me. If Semenov charged 10 times that amount, I would have paid it. It’s that valuable to me.

One thing to pay attention to in that file is content.attr('data-rsDelay’);. Remember that data-* attribute as it’s going to be critical soon.

Third Act: The Style

The “ken Burns Effect”

For this animated project the art director wanted a simple, automatic zoom in/zoom out effect for each image. As each image in the sequence is displayed, zoom it in and then zoom the next one out. This is nothing too dramatic or fancy—just enough to draw the viewer more into the already-immersive animated story being told.

We’ve seen this kind of effect before. It’s a gentle zoom in/zoom out effect documentary moviemaker Ken Burns has put to such good use with old still photographs. Burns has used it so much it’s now a technique that makes his work instantly recognizable. You no doubt noticed the alternating class="kenBurnsIn" and class="kenBurnsOut" in the markup above. Let’s dig deeper into the CSS3 transform effect used to accomplish this.

@-webkit-keyframes Ken-Burns-In {
  0% {-webkit-transform: scale(1);}
  100% {-webkit-transform: scale(1.1);}
@-webkit-keyframes Ken-Burns-Out {
  0% {-webkit-transform: scale(1.1)}
  100% {-webkit-transform: scale(1)}
.kenBurnsIn, .kenBurnsOut {
  -webkit-animation-delay: .4s;
  -webkit-animation-duration: 1.3s;
  -webkit-animation-fill-mode: both;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-transform-origin: top right;
  -webkit-transition: all 4s ease-in-out;
  z-index: 100;
.kenBurnsIn {-webkit-animation-name: Ken-Burns-In;}
.kenBurnsOut {-webkit-animation-name: Ken-Burns-Out;}

First we tell CSS3 (Remember: We’re in charge!) what keyframe animations we’re using (Ken-Burns-In to zoom in, Ken-Burns-Out to zoom out) and at which points of the animation’s timeline CSS3 should act upon them (0% and 100%). Next, we identify what should happen during that time (transform). Finally, we define all the little details like the .4 second delay before each animation starts as well as the overall length of each animation (1.3 seconds). Think of what we’re creating as an overall animation with individual animations inside.

That transform scales the images up from 100% size to 110% (Ken-Burns-In). Then the next image starts scaled at 110% and scales back down to 100% (Ken-Burns-Out). Alternating like this creates that very recognizable Ken Burns-like zoom effect. It’s enough for the viewer to notice but not so much as to distract. Be gentle here.

Fourth Act: The Soundtrack

So far we’ve made our actors move around on stage without talking. Congratulations: It’s the 21st Century and we’ve managed to create the digital equivalent of a silent movie. The thing we have left to do is bring in an audio track and tie all of this animation together into a cohesive experience.

Let’s call this simple bit of HTML5 audio as our narrative soundtrack.

<audio autoplay="true">
  <source src="_audio/new.m4a" type="audio/mp4" />

When I first created this animated movie, I only had to support the Safari browser on an iPad. This MP4 audio file works great for that browser on that device. If you’re going to incorporate a soundtrack, choose the appropriate file format for your target audience. That might mean saving your audio file to multiple formats for use across a wide array of devices and browsers.

Remember that data-rsDelay attribute we saw in Royal Slider’s jquery.rs.autoplay.js file? Notice we’ve now incorporated that into each DIV below. This makes each of those slides appear in sequence using a custom interval. Like the first HTML5 example above, this is only a snippet of the full code. Here’s the full markup.

<div id="slider-with-blocks-1" class="royalSlider">
  <div class="slide1" data-rsDelay="1765">
    <p>Meet Alex.</p>
    <img src="_img/animationMeet.jpg" alt="Meet Alex." class="kenBurnsIn">
  <div class="slide2" data-rsDelay="1834">
    <p>He developed a need.</p>
    <img src="_img/animationDeveloped.jpg" alt="He developed a need." class="kenBurnsOut">
  <div class="slide3" data-rsDelay="3413">
    <p>Luckily for Alex this isn't a disaster.</p>
    <img src="_img/animationDisaster.jpg" alt="Luckily for Alex this isn't a disaster." class="kenBurnsIn">

Let’s take a look at how I arrived at those intervals. I started by opening my audio file in an editor like Fission for Mac. Audacity is a free tool for Mac, Windows, & Linux and works just as well. I listened to the audio and paused each time I wanted the slide to advance. At the bottom of this Fission screenshot the first pause is at 1765, the number that corresponds to data-rsDelay="1765" in the first DIV above. I carefully went through the audio & noted the time of each transition and coded that number into each DIV for a custom interval transition.


Those data-* attributes are really powerful. Think of them as wildcards: Generic handlers to hook into with CSS3 and JavaScript. I’m convinced we’ve only started scratching the surface of what data-* attributes are capable of doing. Watch this space, as we’re ready for a blockbuster sequel.

Finale: Tying It All Together

There we have it! An animated web story using HTML5, CSS3 animation, audio, and a touch of JavaScript and jQuery.

The Sequel

We’ve gone from simple laboratory-based CSS3 animation effects to fully animated storytelling. But I don’t think this is the end of the story. Not by a long shot. In the years to come I imagine sequel after sequel. New CSS3 approaches and further advances in mobile and Responsive Web Design make me think soon we’ll be animating illustrated facial expressions and creating smooth motion effects our Flash friends will be jealous of. Our audiences will expect it.

The End.

Back to the articles