2013-12-03

This summer I started building a modern retelling of "Alice in Wonderland", an interactive storybook web app by the name of Alice in Videoland. It ended up being featured in a sister article in Adobe Inspire as well as turning into an encore-winning presentation I gave at CSS Dev Conf 2013. The project was meant to be educational, a testing ground for new CSS animation techniques and desktop-to-tablet JavaScript. I keep Alice's source up on GitHub where anyone can examine my code, but sometimes it's nice to have someone go over the reasoning with you.

In this article I'll cover some of the most technical details which neither my talk nor the Inspire article could examine in depth:

Using Modernizr.js with animations to enhance graceful degradation

Detecting which page is being read with jQuery Waypoints

Adding scrolling parallax with Skrollr.js

Overcoming scrolling issues and swiping on iPad

Mapping tap to click

If you'd like to learn about storyboarding, retina images, CSS animations, and other interactions, you should check out the supplemental article on Adobe Inspire. Also, before reading further, you should definitely play with the storybook itself!

A Storybook for the iPad and Chrome

My goal was simple enough: make a storybook app that worked equally well in Chrome and on iOS Safari, specifically on the iPad Retina. Mind you, I wasn't designing for a "mobile context", I knew exactly where my target audience would be: on wifi connections, in the comfort of their own homes, either reading with their children on their laps or dissecting the code at the office.

That allowed me to worry less about browser compatibility, a luxury few in production environments can afford. But it's important that we have projects like this that jump ahead of the curve because they help us think about what will be possible tomorrow.

I'd always enjoyed "Alice in Wonderland" and "Through the Looking Glass" growing up, and I dove into researching and developing the new world and characters I'd be creating with zeal. Clear differences in art styles had to be established, from the Impressionist and sterile park of the real world to the mid-century riot of the rabbit's hole.

Each character had to have their own history and personality. Because of tight deadlines, I could only bring a small part of the of the book to life. I started by rewriting the opening scene (which you can read by turning off the CSS or printing the storybook's page) and then creating a storyboard to go with it.

Learn more about the creative process, characters and environment designs that went into "Alice in Videoland" in sister article I wrote for Adobe Inspire.

Graceful Degradation and Progressive Enhancement

From the blinking eye to Alice giving chase, animations are used subtly throughout the story to give the illusion of life, not unlike a popup book. However, while CSS animations are supported in all modern browsers, Internet Explorer 8 and below do not support them. 

If you've checked your site's traffic reports and a significant number of your users rely on Internet Explorer 8 or earlier (you always check your analytics before designing, right?), you can still support those browsers while offering the full interaction to modern browsers. The web development community has faced this problem before and has developed now-common technologies such as web fonts and AJAX. The solution is simple: users on modern browsers get the full experience, while those on less capable browsers still get an intelligible and useful experience. Walt Disney might have called this “plussing” the user experience. Web developers call it “progressive enhancement” or “graceful degradation,” depending on whether you build for older or newer browsers first.

When it comes to animation, I like to take what I call the Pop-Up Book Approach. To illustrate, the following videos are an example of an interactive gift card animation from Square.com engineered by Madelin Woods. (Thanks, Madelin, for recording these!)

People in Internet Explorer 8 and lower will still be delighted by the illustration and won't notice that it should be animated, while people in newer browsers will be entertained at the plussed animation.

In Alice in Videoland, I did the same. In the scene where the hipster white rabbit runs across the screen, I made him centered and stationary if he couldn't be animated. I did this with modernizr.js.

Modernizr.js

Modernizr.js is a small JavaScript helper you can put on a site to check to see if a browser supports certain features like CSS3 animations and transitions. If the features are supported, modernizr adds the classes .cssanimations and .csstransitions to the parent HTML tag.

I set the rabbit's default styles to center him on the page. If transitions are enabled, I use the .csstransitions class to reposition him off the left side of the screen:

Learn more about building animations and retina images in sister article I wrote for Adobe Inspire.

The Loading Screen

It does no good to start playing animations while all the images are still being downloaded. We need to put up a loading screen until everything’s ready to go. jQuery happens to have a method called .load which only fires on just such an occasion. I gave the html tag a default class of .loading and used the following bit of jQuery to change that class to .loaded as soon as the page is fully loaded and rendered:

See the Pen Alice in Videoland Load Screen by Rachel Nabors (@rachelnabors) on CodePen

It’s fairly easy to scope the CSS for the loading screen to the .loading and .loaded classes. Check out line 9 of the CSS in the codepen example. The padding on the container transitions to 0, causing the load screen to “roll up.” Lines 108 to 128 control the animations that cause the cup and saucer to drop after adding the .load class to their container.

Knowing Which Page is Being Read

Some of these animations, like the rabbit running, should only happen when that portion of the story is being read by the reader. It’s hard to know exactly where a user’s eyes will be at a given time, but we can infer it using the lovely jQuery Waypoints plugin. We can use it to assign an .in-view class to each .page when it’s scrolled into view like so:

Then we scope the animation styles to the .in-view class so they only fire after scrolled into view.

Down the Rabbit Hole With Parallax

Originally I was going to animate the background behind Alice, but as the project progressed, I realized that the effect I really wanted was for her to fall toward the bottom of the screen as readers scrolled down. Readers would have to engage with the story to see what happens next, and they would be rewarded not only with a progression toward a goal (the bottom of the page), but also with changes in Alice's mood from frightened, to curious, to sleepy.

First, I had to make Alice sticky. That is, I needed to make her switch to a fixed position after the reader began scrolling, so she wouldn't scroll off the top of the page. I did this using the handy jQuery Waypoints shortcut for sticky elements rather than trying to write my own system.

For the parallax portion, I settled on Skrollr, which works by taking two numerical data attributes on an element, data-pixel-distance and interpolating between them, pixel-distance being the distance from the top of the page at which the changes need to start happening. Since the tunnels are very far down the page, I used JavaScript to measure their distance from the top of the page, and I used their height to get those data attributes:

Which gives me something like:

See the Pen Falling Down the Rabbit Hole by Rachel Nabors (@rachelnabors) on CodePen

 

Scrolling and Swiping on an iPad

In Safari on iOS, when you initiate a scroll, you touch the screen, slide your finger up or down, and then lift your finger off the screen. To save power, Safari doesn't do anything while your finger touches the screen. It stops all animations and doesn't even run JavaScript until you've removed your finger.

Instead, it takes a snapshot of the screen and moves it in the direction of your finger, giving the illusion that you are scrolling as you do on the desktop. But if the page contains animations, the illusion is broken with every scroll of your finger. This means a person could scroll all the way to the bottom of the hole without once stopping to notice that Alice's mood is changing or that she is falling:

Skrollr comes with a mobile-friendly feature by default, which attempts to fix this issue by applying a CSS transform to the entire page and then animating it to a new position with CSS on scroll. However, this method bypasses the scroll events that Waypoints requires to change Alice's attitudes:

Getting Stuck in the Rabbit Hole

This is where I lost steam. I considered setting it up so the falling sequence was an animation on the iPad and a scrolling interaction on desktop, but I loathed the idea. First, I’d have to maintain two separate interactions and second, if I were animating so much of the tale, why didn’t I just make a video of it?

The point of the scrolling interaction is that it pulls readers into the story; they control Alice. They are Alice. It engages them. If all they have to do is click on the rabbit hole, what is the point of that?

I contacted many repo owners and consulted Stack Overflow in search of a solution. It was John Polacek, one of the maintainers of another library Super Scrollorama, who suggested I take a look at Hammer.js, a small JavaScript library for handling gestures like pinching and swiping on mobile devices (which has a version that plugs directly into jQuery!) I had looked at the library early on in development and opted against pursuing it, but I decided to look again.

It's Hammer Time

I spent a lot of time watching how people moved through the story using touch on iPad. I noticed that they weren't scrolling down the page so much as swiping. I thought if I could map advancing the story by one page to a swiping action, I could still maintain a pretty close relationship between both desktop and touch experiences. Hammer.js allowed me to hook into swipe events on the iPad, and I was able to make it so that on swipe, readers advanced to the next page:

This is a massive simplification of the code. For this touch-based use case, I had to resort to keeping track of the current, previous, and next pages using counter variables. There are also some interesting things happening with recalculating heights and such on changing environments. I highly recommend you take a look at the (helpfully annotated!) source code if you really want to get your hands dirty.

Tapping vs. Clicking

One of the problems with developing for iPads is that clicks do not map directly to taps. When you tap a link in iOS Safari, there is a slight pause while the system double checks that you’re not going to make some kind of gesture. It’s asking, “Are you sure you want to follow that link? Or are you pinching or double tapping?” This makes click-based interactions feel sluggish and unnatural.

In our case, when the rabbit hole is clicked or tapped, we want it to execute the downTheHole() function which scrolls the page down into the earth. The solution is to use both click and touchend event listeners! Rodney Rehm helped me make a more efficient version of my original activate() method. After which, it’s easy to call like so:

A Work in Progress

Alice in Videoland will always be a work in progress for me. As time allows, I can go back to expand the number of devices and browsers she performs seamlessly in. Or I can move forward and add new chapters to the story to demonstrate things like canvas, SVG animations, or the web animation API.

I'm always open to new ways to write code and make old code run faster. I hope that "Alice" will serve as a long and storied demo of things just around the corner for interaction design.

Show more