An Elegant App - Part 2

An Elegant App - Part 2

By Bryan Maynard, OCI Software Engineer

August 2012


Introduction

This is the second installment in a four part series on building an elegant application for the web. In the previous article we looked at designing our application's user interface for mobile devices first and scaling up to larger, more capable devices. In this article we will be looking at how CSS Animations can augment our application's user interface, making our application more pleasant to use and intuitive.

Why do we need animations?

In our profession we spend a lot of time with software. This makes it easy to lose sight of how complex and bewildering our application interfaces can be to users who haven't spent as much time with them as we have. Building interfaces the average person can understand and intuit requires looking beyond our familiarities.

Let's forget software for just a minute and talk about the real world. In the real world, do things appear out of thin air? How would you respond if you paid for a Clif Bar and it moved from the checkout lane to your pocket quicker than you could blink your eyes? If you pushed a door to walk into Starbuck's and the door disappeared, what would you do?

While software applications are not physical objects, our application's user interfaces do need to follow some of the real world's conventions. In the real world things have state transition gradually instead of switching instantly. For a Clif bar to make it to my pocket, it must first be moved from the register. When I push on a door to enter a Starbuck's, that door swings open.

The more time a user spends dealing with real world objects, the more they expect our user interfaces to follow the conventions of real world objects. They will expect forward progress through a set of steps to be conveyed via right-to-left visual motions. They will expect important content to be revealed, not merely shown.

In the real world everything comes from somewhere. To help our users maintain the association between different parts of our application, we must provide visual clues in our interface as to where each part of our application comes from and how those parts relate to each other.

For example, sliding content up from the bottom of the page would indicate that the new content is more specific, or more narrowly focused, than the content that preceded it. In a multi-step wizard, sliding the screen right-to-left as the user progresses indicates forward progress.

What are CSS animations?

CSS Animations are a portion of the W3C's CSS3 specification that govern gradually changing an element's style over time from one value to another.

CSS Animations are defined by specifying at least two keyframes:

  1. @keyframes
  2. my-first {
  3. 0% { background: red; }
  4. 100% { background: yellow; }
  5. }

The animation my-first would then be bound to div elements as follows:

  1. div {
  2. animation: my-first 5s;
  3. }

This rule specifies that the my-first animation should take 5 seconds to complete. Since we have not provided any classes or attribute values to match against, this CSS Animation will begin executing on a div as soon as it is added to the document - including the initial page load.

You may specify more than two keyframes. If you do, each keyframe must be assigned a point in the animation:

This animation defines four distinct stages and may be bound to an element in the same way as the first example.

When are animations appropriate?

CSS Animations allow elements of an application's ui to "come from" somewhere, giving them purpose and context. They provide visual links between pieces of our application.

A CSS Animation is appropriate to the extent that it satisfies one or more of the following criteria:

CSS Animations do not need to be long or drawn out. A fraction of a second is often enough to do what is needed. We do not want to slow our user down by adding animations to our interface.

Snappy, sensible animations make our user interface feel more approachable, understandable, and polished. Slow, overblown, flashy animations frustrate users and make our interface feel gaudy and cheap.

This article will show how AiOIM's CSS Animations for the user list, chat session window, and user messages are defined.

A non-standard standard

One thing needs to be noted about CSS Animations before we proceed: they are currently implemented via vendor prefixes. This means that to provide support for all modern browsers (Safari, Google Chrome, IE, Opera, etc) CSS files containing animations become rather large. To support the widest range of users, our first example animation would need to be written as follows:

  1. @keyframes my-second {
  2. 0% { background: red; }
  3. 25% { background: yellow; }
  4. 50% { background: blue; }
  5. 100% { background: green; }
  6. }
  1. // Official W3C syntax
  2. @keyframes my-first {
  3. 0% { background: red; }
  4. 100% { background: yellow; }
  5. }
  6. // For WebKit (Google Chrome, Safari, etc)
  7. @-webkit-keyframes my-first {
  8. 0% { background: red; }
  9. 100% { background: yellow; }
  10. }
  11. // For Firefox
  12. @-moz-keyframes my-first {
  13. 0% { background: red; }
  14. 100% { background: yellow; }
  15. }
  16. // For IE
  17. @-ms-keyframes my-first {
  18. 0% { background: red; }
  19. 100% { background: yellow; }
  20. }
  21. // For Opera
  22. @-o-keyframes my-first {
  23. 0% { background: red; }
  24. 100% { background: yellow; }
  25. }

Tools like Stylus can minimize the need for repetitious typing, but nothing except careful use of animations can mitigate the danger of bloated CSS files that take a long time to load.

In my experience, sensible use of simple animations does not cause any noticeable impact of page load time. This does, however, present a powerful reason to stay away from needless, overly flashy CSS Animations.

In this article, to save space, I will show only the official W3C syntax for animations.

User list

The user list animation is defined as follows:

  1. @keyframes slide_down-fade_in {
  2. 0% {
  3. top: 2em;
  4. opacity: 0;
  5. box-shadow; 0 0 0 black;
  6. }
  7. 100% {
  8. top: 2.5em;
  9. opacity: 1;
  10. box-shadow: 0 3px 15px black;
  11. }
  12. }
  13. @keyframes slide_up-fade_out {
  14. 0% {
  15. top: 2.5em;
  16. opacity: 1;
  17. box-shadow: 0 3px 15px black;
  18. }
  19. 100% {
  20. top: 2em;
  21. opacity: 0;
  22. box-shadow: 0 0 0 black;
  23. }
  24. }

Sliding down as the user list appears communicates that the list "came from" the search box. This strengthens the connection between these two UI elements for the use.

Also keep in mind that our user does not know exactly what to expect when they start typing in AiOIM's user search field. Flashing a user list into view as a result of their typing would be surprising. Fading the list into view gives the user time to realize what's happening and relate the user list to the text they entered.

New messages

The animations for messages are:

  1. @keyframes slide_in-self-message {
  2. 0% {
  3. opacity: 0;
  4. right: -19em;
  5. }
  6. 100% {
  7. opacity: 1;
  8. right: 0em;
  9. }
  10. }
  11. @keyframes slide_in-other-message {
  12. 0% {
  13. opacity: 0;
  14. left: -19em;
  15. }
  16. 100% {
  17. opacity: 1;
  18. left: 0em;
  19. }
  20. }


This defines two animations: one that fades a message in as it slides from left to right (a message from someone other that our user) and one that fades a message in as it slides from right to left (a message from our user).

As people, we understand that conversations between two people are bi-directional. Films translate this idea to a two-dimensional space by assigning conversation participants areas, or regions, of the screen. This helps viewers quickly identify who is who as the camera changes focus from person to person. In a conversation with two participants, one is assigned the left side of the screen and one the right.

AiOIM already has a slight notion of this convention. Messages we send are indented slightly so they appear on the "right side" of the chat window compared to messages sent from others - which appear to be more on the "left side".

To follow the film convention for conversations even more closely, we will apply the animations created above to new messages. Once these animations are applied, messages from others will slide into view from the left - effectively placing other user on the left side of our chat screen. Messages from us will slide in from the right - effectively placing us on the right side of our chat screen.

Chat session window

The animations for the chat session window are:

  1. @keyframes slide_down-fade_in_messages {
  2. 0% {
  3. margin-top: 0;
  4. opacity: 0;
  5. box-shadow: inset 0 2px 5px rgba(0,0,0, .5), 0 0 0 rgba(0,0,0, .7);
  6. }
  7. 50% {
  8. margin-top: 0;
  9. opacity: 0;
  10. box-shadow: inset 0 2px 5px rgba(0,0,0, .5), 0 0 0 rgba(0,0,0, .7);
  11. }
  12. 100% {
  13. top: .5em;
  14. opacity: 1;
  15. box-shadow: inset 0 2px 5px rgba(0,0,0, .5), 0 5px 10px rgba(0,0,0, .7);
  16. }
  17. }
  18. @keyframes slide_in-user_name {
  19. 0% {
  20. margin-left: -.1em;
  21. opacity: 0;
  22. text-shadow: 0 0 0 transparent, 0 0 0 transparent;
  23. }
  24. 100% {
  25. margin-left: .4em;
  26. opacity: 1;
  27. text-shadow: 0 -1px #FFD8A6, 0 1px 0 #A66B1F;
  28.  
  29. }
  30. }

To support the relationship between the user search box and a chat session visually we make sure that selected user's name slides into view before the chat window appears. By making it appear that the user's name "comes from" the search box instead of the user list we are communicating to our user that the search box, not the user list, is how they find users to chat with.

Additionally, by waiting until after the user's name has faded in to show the chat window we communicate that the chat "comes from" the user we found. We are also using the "slide down" animation consistently.

Staggered animations

The chat window animations introduce an interesting technique for managing animations across multiple elements: staggered animations.

A staggered animation has one main element, and one or more dependent animations. The main animation in our choreography is slide_in-user_name. The dependent animation is slide_down-fade_in_messages. We do not want the chat window to begin fading into view or sliding down until the user's name has faded into view. To achieve this, we assign the animations as follows:

  1. #aioim .chatting.with li.active .user.name {
  2. animation slide_in-user_name .33s
  3. }
  4. #aioim .chatting.with li.active .messages {
  5. animation slide_down-fade_in_messages .66s
  6. }

This means that when a conversation (represented by an li HTML element) has the active class applied both the slide_in-user_name and slide_down-fade_in_messages will begin executing simultaneously. When the slide_in-user_name has completed the slide_down-fade_in_messages animation will at 50%.

A staggered animation may have more than one dependent animation, and dependency chains may be setup if needed.

In conclusion

CSS Animations are a powerful tool. By following a few simple guidelines we can use CSS Animations to make our user interfaces more intuitive, less intimidating, and more attractive.

To see the results of the code shown above, please go to aioim.bryanmaynard.com

secret