Chapter 9. Motion and color – Hello! HTML5 & CSS3: A user-friendly reference guide

Chapter 9. Motion and color

 

This chapter covers

  • Making elements semitransparent with the opacity property
  • Making colors semitransparent with RGBA
  • A new, more intuitive way to specify color: HSL and HSLA
  • Natural user interaction with transitions and animation

 

In this chapter, we’ll look at some of the snazzier aspects of CSS3—features that are much loved by graphic designers.

Colors and opacity

In the beginning, the web was black and white, but these days there aren’t many websites that don’t make extensive use of color. It’s unlikely the web will revert to black and white any time soon, so it’s a good thing CSS3 includes several new features for colors. Later in this section, you’ll learn about RGBA, HSL, and HSLA. First, though, let’s investigate how CSS3 allows you to achieve another popular effect in modern web design: semitransparency with the opacity property.

Opacity

Opacity is a measure of what percentage of light is blocked by an object. In the case of HTML and CSS, the objects are elements on the page. They are, by default, fully opaque; no light is allowed through, so you can see nothing of the elements beneath (that is, earlier in the source code). If a paragraph has a blue background, it completely obscures any background on the element that contains the paragraph.

Browser support quick check: opacity

 

Standard

Prefixed

1.0 -
1.0 0.8
9.0 -[*]
9.0 -
1.2 1.0

* IE has been able to do transformations with the nonstandard filter attribute since version 5.5.

Opacity can be used to de-emphasize page elements to let your user focus on a single important task. This is commonly seen on the web in the ubiquitous lightbox, shown in action here.

Before: The normal busy page. The user has lots of options.

After: The rest of the page is hidden behind a semitransparent layer so the user can concentrate on the picture.

The opacity property is straightforward: you specify a value between 0 and 1. The fully opaque default is 1, and 0 is fully transparent:

div {
    background-color: #666;
    color: #ccc;
    border: 4px solid #ccc;
}
div:nth-child(1) { opacity: 1; }
div:nth-child(2) { opacity: 0.8; }
div:nth-child(3) { opacity: 0.6; }
div:nth-child(4) { opacity: 0.4; }
div:nth-child(5) { opacity: 0.2; }
div:nth-child(6) { opacity: 0; }

When all the elements are sitting against the same white background, the effect of decreasing opacity is the same as using lighter colors. The full code for this example is in ch09/opacity-1.html.

A common use of opacity is to make a continuous pattern or background image always be visible without clashing with the main content. Here the <h1> element lies on top of the <div> that contains it, but opacity is used to let the background of the <div> be partly visible through the <h1>:

body  {
     background-color: #666;
}
div {
    background: url(example.png)
      no-repeat 50% 50%;
}
h1 {
    background-color: #fff;
    color: #000
    opacity: 0.75;
}

Here’s the markup. You can see the full listing in ch09/opacity-4.html:

<body>
    <div><h1>Opacity is cool</h1></div>
</body>

Although the opacity property isn’t inherited in the CSS sense, the opacity of the parent element affects that of its child elements. In the following example, on the right (listing ch09/opacity-2.html), all the child elements are invisible because they’re contained within an element that isn’t visible, regardless of their individual opacity values. This is the same as setting an element to visibility: hidden—the element isn’t visible, but it’s still taking up space on the page. On the left (listing ch09/opacity-3.html), the outer element is fully visible, but transparent child elements don’t cut holes in their opaque parents.

Descending opacity

Ascending opacity

 
div > div > div > div > div > div
  { opacity: 0; }
div > div > div > div > div
  { opacity: 0.2; }
div > div > div > div
  { opacity: 0.4; }
div > div > div { opacity: 0.6; }
div > div { opacity: 0.8; }
div { opacity: 1; }
div > div > div > div > div > div
  { opacity: 1; }
div > div > div > div > div
  { opacity: 0.8; }
div > div > div > div
  { opacity: 0.6; }
div > div > div { opacity: 0.4; }
div > div { opacity: 0.2; }
div { opacity: 0; }
<div><div><div><div><div><div>
                        opacity : 0
                    </div>
                    opacity : 0 . 2
                </div>
                opacity : 0 . 4
            </div>
            opacity : 0 . 6
        </div>
        opacity : 0 . 8
    </div>
    opacity : 1
</div>
<div><div><div><div><div><div>
                        opacity : 1
                    </div>
                    opacity : 0 . 8
                </div>
                opacity : 0 . 6
            </div>
            opacity : 0 . 4
        </div>
        opacity : 0 . 2
    </div>
    opacity : 0
</div>

RGBA

Sometimes you don’t want to make an entire element transparent or semi-transparent. If you refer back to the example from listing ch09/opacity-4.html, the text and the background are semitransparent.

If you want people be able to read large amounts of text like this, then a semitransparent background would be better combined with fully opaque text. Rather than make the entire element semitransparent, CSS3 provides several ways of specifying color values that have a level of transparency, the first of which is rgba(). You can use rgba() to make just the background transparent. If you’re used to the hexadecimal shorthand for specifying colors, these two diagrams show how they’re related.

50% opacity element with a dark gray background

Element with a background that is both dark gray and 50% opacity

Browser support quick check: rgba()

 

Full

Partial

2.0 -
3.0 -
9.0 -
10.0 -
3.1 -

The primary benefit is that the opacity is now confined to the background—the rest of the element’s contents and attributes can be full opacity.

The difference is even more pronounced for the nested element example, where previously setting the outer element to transparent made the entire set of elements disappear.

See the full code for this example in listing ch09/rgba-2.html.

With transparency confined to the background and not inherited, the text and borders remain visible on all the elements:

div > div > div > div > div > div {
  background-color:
    rgba(102,102,102, 1); }
div > div > div > div > div {
  background-color:
    rgba(102,102,102, 0.8); }
div > div > div > div {
  background-color:
    rgba(102,102,102, 0.6); }
div > div > div {
  background-color:
    rgba(102,102,102, 0.4); }
div > div {
   background-color:
     rgba(102,102,102, 0.2); }
div {
   background-color:
     rgba(102,102,102, 0); }

See listing ch09/rgba-3.html for the full code.

HSL and HSLA

You may have found yourself wanting a darker shade of a particular color as a contrasting element in one of your designs. This is easy to manage in simple cases with RGB—just make the numbers smaller, as in the next example.

Browser support quick check: hsl() and hsla()

 

Full

Partial

2.0 -
3.0 -
9.0 -
10.0 -
3.1 -

For those of you reading this book on paper in black and white, the top pair of elements that follow are shades of gray, the middle pair are shades of blue, and the bottom pair are a sort of purple/pink combination:

.one {
  background-color:
    rgb(204,204,204);
  color: rgb(102,102,102);
}
.darkone {
  background-color:
    rgb(102,102,102);
  color: rgb(204,204,204);
}
.two {
  background-color: rgb(51,102,153);
  color: rgb(17,34,51);
}
.darktwo {
  background-color: rgb(17,34,51);
  color: rgb(51,102,153);
}
.three {
  background-color: rgb(232,44,122);
  color: rgb(83,9,40);
}
.darkthree {
  background-color: rgb(83,9,40);
  color: rgb(232,44,122);
}

Although in all three pairs the second color is a darker shade of the first color, it gets increasingly difficult to see the relationship in the pairs as the numbers become less regular.

HSL stands for hue, saturation, and luminosity in the same way that RGB stands for red, green, and blue. The basic color is provided by the hue, and the saturation determines the intensity of the color—lower saturation means more grey. The luminosity determines how light or dark the color is. Here’s the same set of colors using HSL notation:

.one {
  background-color: hsl(0,0%,80%);
  color: hsl(0,0%,40%);
}
.darkone {
  background-color: hsl(0,0%,40%);
  color: hsl(0,0%,80%);
}
.two {
  background-color:
         hsl(210,50%,40%);
  color: hsl(210,50%,13.3%);
}
.darktwo {
  background-color:
         hsl(210,50%,13.3%);
color: hsl(210,50%,40%);
}
  .three {
  background-color:
         hsl(335,80%,54%);
  color: hsl(335,80%,18%);
}
.darkthree {
  background-color:
         hsl(335,80%,18%);
  color: hsl(335,80%,54%);
}

In HSL, the luminosity of the color is controlled by one parameter. The relationship between the colors is therefore far more obvious from the code, because this is the only parameter that changes.

Here’s what happens when you vary only the saturation. It’s hard to make out the differences in a black-and-white book, so I’ll describe them: the box at the top is light blue, and the one at the bottom is gray.

Open the example file to get a better look at the colors: ch09/colors-hsl-3.html.

If only the hue is varied, you get different colors with the same saturation and luminosity. The hue corresponds to a point on a color wheel, measured in degrees—360 and 0 are the same hue. Using four evenly spaced points for this example yields a blue, two shades of green, and a red.

Unfortunately, because the colors have the same saturation and luminosity, they’ll be even harder to tell apart in black and white. Open the example file to see for yourself: ch09/colors-hsl-4.html.

HSL has a semitransparent equivalent: HSLA. Like RGBA, it has a final parameter that specifies the percentage opacity:

.one {
  background-color:
    hsla(210,75%,40%,1);
  color: hsl(210,75%,13.3%);
}
.two {
  background-color:
    hsla(210,75%,40%,0.66);
  color: hsl(210,75%,13.3%);
}
.three {
  background-color:
    hsla(210,75%,40%,0.33);
  color: hsl(210,75%,13.3%);
}
.four {
  background-color:
    hsla(210,75%,40%,0);
  color: hsl(210,75%,13.3%);
}

CSS transforms

Browser support quick check: 2D transforms

 

Full

Partial

- 7.0
- 3.5
- 9.0[*]
- 10.5
- 3.1

* IE has been able to do transformations with the nonstandard filter attribute since version 5.5.

In chapter 3, you learned about transforms using the <canvas> element and SVG—these let you rotate, scale, and skew elements. Similar functionality is made available as part of CSS3. Because everything uses the same rendering engine (the browser), this shouldn’t be too surprising. It’s already implemented—the browser is just offering different ways to activate it. Transforms allow your designs to escape the rectangular world of standard web pages.

2D transforms

To demonstrate CSS 2D transforms, we’ll use this simple page with three similar elements:

<body>
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</body>

Here’s the basic CSS:

div {
    display: inline-block;
    padding: 1em;
    margin: 1em;
    background-color: #666;
    color: #fff;
}

This example picks out the second element and scales it to 150% of its initial size:

div:nth-child(2) {
    transform: scale(1.5);
}

By default, transformed elements keep their center point in the same place. If you scale the third element to 250% of its original size, it partially covers the second element:

div:nth-child(3) {
    transform: scale(2.5);
}

The static point around which the transform is applied can be changed with the transform-origin property. Here we set the third element to expand from its left outward:

div:nth-child(3) {
    transform-origin: left;
    transform: scale(2.5);
}

You can also rotate elements:

div:nth-child(1) {
  transform: rotate(16.5deg);
}
div:nth-child(2) {
  transform: rotate(33deg);
}
div:nth-child(3) {
  transform: rotate(66deg);
}

When the elements are rotated around their centers, the visual spacing can look a little odd. In this example, transform-origin is set for each element to bring the elements closer together:

div:nth-child(1) div {
  transform-origin: bottom right;
  transform: rotate(16.5deg);
}
div:nth-child(2) div {
  transform-origin: top right;
  transform: rotate(33deg);
}
div:nth-child(3) div {
  transform-origin: top left;
  transform: rotate(66deg);
}

In this screenshot, the original positions of the elements have been drawn in so you can more easily see that each element is rotating around a different reference point.

The skew functions allow you to create perspective-like effects. Horizontal skewing is achieved with skewX and vertical with skewY:

div:nth-child(1) {
  transform: skewX(16.5deg);
}
div:nth-child(2) {
  transform: skewY(33deg);
}
div:nth-child(3) {
  transform:
   skewX(16.5deg) skewY(33deg);
}

It’s also possible to move elements around on the page with translateX and translateY:

div:nth-child(1) {
  transform: translateX(50px);
}
div:nth-child(2) {
  transform: translateY(50px);
}
div:nth-child(3) {
  transform:
    translate(-50px, -50px);
}

For this trick, you need to add an extra <div> to the markup to preserve the direction of the content in the top face:

<div class="cube">
    <div>
        <div>One</div>
    </div>
    <div>Two</div>
    <div>Three</div>
</div>

The faces are then skewed by 30 or -30 degrees and positioned so the edges line up. Colors are set on each face individually to enhance the perception of depth.

See the blog post “3D Cube using 2D CSS transformation” by Paul Hayes for a full explanation of this technique: www.paulrhayes.com/2009-04/3d-cube-using-css-transformations/.

.cube div:nth-child(1) div,
.cube div:nth-child(2),
.cube div:nth-child(3) {
    padding: 10px;
    width: 180px;
    height: 180px;
}
.cube > div {
    position: absolute;
}
.cube div:nth-child(2) {
    transform: skewY(30deg);
    background-color: #444;
}
.cube div:nth-child(3) {
    transform: skewY(-30deg);
    background-color: #666;
    left: 200px;
}
.cube div:nth-child(1) div {
    transform:
      skewY(-30deg) scaleY(1.16);
    background-color: #888;
    font-size: 0.862em;
}
.cube div:nth-child(1) {
    transform: rotate(60deg);
    top: -158px;
    left: 100px;
}

3D transforms

Tricks with transform, translate, and skew are entertaining, but they aren’t a substitute for real three-dimensional transformations. The example in the previous section is subtly off—it doesn’t represent a proper perspective rendering of a cube and the sides don’t quite line up. Fortunately, the CSS Working Group is working on a standard for transformations in three dimensions.

Browser support quick check: 3D transforms

 

Full

Partial

- 12.0[*]
- 10.0[*]
- 10.0
- -
- 4.0[*]

* Support for 3D transforms requires the presence of a compatible graphics card driver.

This time, because you’re making an actual cube in a 3D space, you need six elements to form the sides:

<div class="cube">
    <div class="one"><p>One</p></div>
    <div class="two"><p>Two</p></div>
    <div class="three"><p>Three</p></div>
    <div class="four"><p>Four</p></div>
    <div class="five"><p>Five</p></div>
    <div class="six"><p>Six</p></div>
</section>

The first step in 3D transformations is to set a perspective. This defines the depth of the 3D space within which you’ll be positioning the transformed elements:

body { perspective: 1000; }

Next, because you want all six sides of the cube to be transformed within the same 3D space, you set a transform-style value of preserve-3d on the parent element:

div.cube {
    transform-style: preserve-3d;
    position: relative;
}

To start with, all six sides will be stacked on top of each other with absolute positioning:

div.cube > div
    { position: absolute; color: #fff;
      width: 200px; height: 200px; }

Now the individual sides are transformed in 3D. Each side is rotated so it faces the correct way and then translated along the z-axis by 100 pixels (because the sides of the cube are 200 pixels deep). The z-axis is the third dimension available in the 3D space. Because the rotation occurs before the translation, each side is pushed away from the center of the cube in a different direction:

.one {
    transform: translateZ(100px);
    background: rgba(136,136,136,0.5);
}
.two {
    transform: rotateY(90deg) translateZ(100px);
    background: rgba(102,102,102,0.5);
}
.three {
    transform: rotateX(-180deg) translateZ(100px);
    background: rgba(68,68,68,0.5);
}
.four {
    transform: rotateY(-90deg) translateZ(100px);
    background: rgba(34,34,34,0.5);
}
.five {
    transform: rotateX(90deg) translateZ(100px);
    background: rgba(153,153,153,0.5);
}
.six {
    transform: rotateX(-90deg) translateZ(100px);
    background: rgba(34,34,34,0.5);
}

Finally, the whole cube is rotated in the z- and x-axes for artistic effect:

div.cube {
    transform: rotateZ(-45deg) rotateX(45deg);
}

CSS transitions

A transition is a short animation between two element states, such as activating a drop-down menu or closing a pop-up message. Instead of having the elements immediately appear or disappear, the menu might slide down, and the pop-up message could fade out. Such effects improve usability by making interfaces more realistic and can be used to clarify relationships.

One simple way to apply transitions is with a dynamic pseudo-class like :hover. In the following sets of screen-shots, three of the transformation examples from the previous section have been applied to the :hover state of a containing <div> with a transition lasting 10 seconds. Instead of flipping from one state to the other, the change happens gradually. If you look carefully, the fly-like speck on each screenshot is the mouse pointer.

Browser support quick check: CSS transitions

 

Full

Partial

- 7.0
- 4.0
- 10.0
- 10.5
- 3.1

This example is from ch09/transforms-5.html with a 10-second transition.

This example is from ch09/transforms-6.html with a 10-second transition.

This example is from ch09/transforms-7.html with a 10-second transition:

The transition-duration property is the only thing required to create the animation:

div div {
    transition-duration: 10s;
}

Although all three elements have unique states when the parent element is hover, all three are transitioned according to the previous rule. Look at ch09/transitions-1.html to see for yourself.

div:hover div:nth-child(1) {
    transform-origin: bottom right;
    transform: rotate(16.5deg);
}
div:hover div:nth-child(2) {
    transform-origin: top right;
    transform: rotate(33deg);
}
div:hover div:nth-child(3) {
    transform-origin: top left;
    transform: rotate(66deg);
}

When transition-duration is set on the default state of the element (in this case, when it isn’t hover), the same duration applies as the transition runs both forward and backward—as the element enters the hover state and leaves it, the transition will last 10 seconds as shown in the results of listing ch09/transitions-3.html.

But you can put transition-duration on the hover state. In this case, it will only apply as the element enters the hover state. When the element leaves hover, it immediately snaps back to the starting position—a duration of zero.

This is the critical bit of code from listing ch09/transitions-4.html:

div:hover div { transition-duration: 10s; }

You can also put transition-duration on both states. In the next example, the transition lasts 10 seconds as it enters the hover state and 5 seconds as it exits.

The duration for exiting the hover state is specified on the rule without the :hover:

div div { transition-duration: 5s; }
div:hover div { transition-duration: 10s; }

See the complete example in listing ch09/transitions-5.html.

Transition timing functions

By default, transitions happen at a constant rate, but you can adjust that with the transition-timing-function property. The default value is linear, but several other keywords are available: ease-in-out, ease-in, ease-out, and ease. The difference is much easier to see than it is to explain, so the next four screenshots show the values in operation side by side over a 20-second transition.

The quickest out of the blocks is ease-out, followed by ease. Both ease-in-out and ease-in are initially slower-moving than linear.

A few seconds later, ease has overtaken ease-out.

As you go past the halfway point, ease-in-out has accelerated and is ahead of linear.

Toward the end of the transition, ease-in is starting to catch up with the rest; remember, all five transitions take 20 seconds to complete.

The non-linear transition timings often appear more natural—things tend to accelerate and decelerate rather than suddenly start and stop moving.

You’re also not limited to effects on hover; any other dynamic pseudo-class will work just as well. With a slight modification, the :target example from chapter 7 can be made to fade smoothly in and out.

1. The page loads blank.

2. When you click the first link, the content starts to fade in.

3. After 10 seconds, the transition completes.

4. Clicking the second link starts two transitions. The current text starts to fade out...

5. ...as the new page starts to fade in.

6. After 10 seconds, the new content has replaced the old.

The HTML is similar to that in chapter 7. All that’s been added is a <section> element to allow the paragraphs to be absolutely positioned:

<menu>
    <a href="#one">Show one</a>
    <a href="#two">Show two</a>
    <a href="#three">Show three</a>
    <a href="#four">Show four</a>
</menu>
<section>
    <p id="one">I never am really satisfied...</p>
    <p id="two">In almost every computation...</p>
    <p id="three">Many persons who are not conversant...</p>
    <p id="four">The Analytical Engine has no pretensions...</p>
</section>

The paragraphs then fade in and out over 10 seconds. The fade-in uses the timing function ease-in (start slow and finish fast), and the fade-out uses ease-out so the disappearing paragraph begins to fade out as quickly as possible, giving immediate feedback to the user:

section { position: relative; }
p {
    opacity: 0;
    position: absolute;
    transition-duration: 10s;
    transition-timing-function: ease-out;
}
p:target {
    opacity: 1;
    transition-timing-function: ease-in;
}

See the full source code in ch09/transitions-6.html.

Transition property

So far, the examples have implicitly chosen which properties they will apply to by only listing the changed ones in the transition state. Every property has therefore been subject to the same duration and timing function. But it’s possible to apply multiple transitions to the same element, with each one affecting a different property.

In this section, you’ll take advantage of the fact that all the transition properties accept multiple properties in a comma-separated list. You can declare two transition durations, one of 10 seconds and one of 20, like this:

transition-duration: 10s, 20s;

Then, if you declare transition-property like this

transition-property: top, transform;

the transition of the top property will take 10 seconds, and the transition of the transform property will take 20 seconds. The next example compares two elements with the same transition duration but different transition properties.

As you can see, element one drops quickly and expands slowly, whereas element two expands quickly and drops slowly. The markup is two <div> elements inside a <section> with this CSS applied to it:

section div {
    position: absolute;
    top: 0px;
    transition-duration: 10s, 20s;
    transition-property: top, transform;
}
section div:nth-child(2) {
    left: 200px;
    transition-property: transform, top;
}
section:hover div {
    top: 280px;
    transform: scale(1.5);
}

Transition delay

You don’t have to start a transition immediately after whatever action initiated it. The transition-delay property allows you to specify a wait before a transition starts. In the following screenshots, element two doesn’t begin transitioning until five seconds after element one started, and element three’s transition begins a further five seconds after that.

The code, from listing ch09/transition-delay-1.html, is identical to that from ch09/transitions-3.html except for these two rules:

div div:nth-child(2) { transition-delay: 5s; }
div div:nth-child(3) { transition-delay: 10s; }

The most common use for transition-delay is to chain a number of transitions together. If you want an element to first move and then enlarge, you specify two transitions like this:

div {
    transition-duration: 10s, 10s;
    transition-delay: 0, 10s;
    transition-property:  top, transform;
}

The element will first transition the top value and then transition the transform. You can see a full example in the code file ch09/transition-delay-2.html. With transition-delay, it’s possible to create multiple-step animations, providing that at each step a different property is transitioned. For a more complete approach to animation with CSS, see the later section “CSS Animation.”

Triggering transitions with JavaScript

After a transition is defined on an element, any change in the computed style will trigger the animation. This doesn’t have to be due to a dynamic pseudo-class taking effect; you can also change the styles with JavaScript.

Clicking the Change Left button starts an animation.

Over 10 seconds, the element moves to the left.

Similarly, clicking Change Top starts another animation.

Over 10 seconds, the element moves down from the top of the page.

Here’s the HTML for the page:

<menu>
    <button onclick="clickme('changeleft')">Change left</button>
    <button onclick="clickme('changetop')">Change top</button>
    <button onclick="clickme('changecolor')">Change color</button>
    <button onclick="reset()">Reset</button>
</menu>
<div id="animateme">Animate Me</div>

The CSS defines the animation and three classes that adjust the relevant properties:

#animateme {
    background-color: #666;
    position: absolute;
    color: #fff;
    left: 100px;
    top: 100px;
    transition-duration: 10s;
}
.changeleft { left: 250px !important; }
.changetop { top: 300px !important; }
.changecolor { background-color: #ff00ff !important; }

Note that you must use !important because otherwise the ID selector would take precedence. Finally, here’s the JavaScript function to apply the styles to the element when the buttons are clicked:

function clickme(classname) {
    var el = document.getElementById('animateme');
    el.className += " " + classname;
}

And here’s a reset function to clear the styles:

function reset() {
    var el = document.getElementById('animateme');
    el.setAttribute("style","");
}

This example switches to Opera so you can take advantage of the color input type.

Set the left and top to 200 and the color to a light blue.

The element animates over 10 seconds as before.

The animation is complete.

Set the left to 0, the top to 300, and the color to black.

The element animates from its current position.

After 10 seconds, the new properties are in effect.

<menu>
    <button onclick="clickme()">Click Me</button>
    <button onclick="reset()">Reset</button>
    <label for="myleft">left</label>:
        <input id="myleft" type="number" value="100">
    <label for="mytop">top</label>:
        <input id="mytop" type="number" value="100">
    <label for="mycolor">color</label>:
        <input id="mycolor" type="color" value="#666666">
</menu>
<div id="animateme">Animate Me</div>
function clickme() {
    var el = document.getElementById('animateme');
    var left =  document.getElementById('myleft').value;
    var top =  document.getElementById('mytop').value;
    var color =  document.getElementById('mycolor').value;
    el.setAttribute("style","left: " + left + "px; top: " + top +
        "px; background-color: " + color + ";");
}

CSS Animation

CSS Animations are a way of chaining multiple transitions together on the same property to be performed one after the other. Transitions are always linear—a single transition can move an element from one location to another, but it can’t move it to a third location after that. Although you can chain transitions together using transition-delay, this technique quickly becomes unwieldy for more than a few steps, and you can still transition only one property at a time. You could, of course, perform a whole sequence of transitions with JavaScript, but that would defeat the purpose of transitions—a declarative solution for simple animations.

Browser support quick check: CSS Animation

 

Full

Partial

- 4.0
- 5.0
10  
- 12
- 4.0

This first example makes an element bounce up and down.

To declare an animation, use the @keyframes directive. The first word after the directive is the name of the animation, followed by a list of keyframes in braces. Keyframes are defined by the keywords from or to, or a percentage value:

@keyframes bounce {
    from { top: 50px; }
    25% { top: 350px; }
    50% { top: 50px; }
    75% { top: 350px; }
    to { top: 50px; }
}

For each keyframe, you provide a semicolon-separated list of CSS properties, just as in a normal CSS rule. For best effect, these should be properties that can be transitioned; then the browser can take care of the intermediate animation. The previous keyframes set the top of the element to be alternately 50 and then 350 pixels.

To apply the animation to an element, use the animation-name property:

#animateme {
    position: absolute;
    left: 100px;
    top: 50px;
    animation-duration: 20s;
    animation-name: bounce;
    animation-iteration-count: infinite;
}

This rule also sets an animation-duration—this works the same way as transition-duration. The animation will run for 20 seconds, so you can calculate that the element will have a value of 350 pixels for top after 5 seconds: there are four steps after the from state, and 5 is 25% of 20 seconds. You can also specify animation-iteration-count—this can be a fixed value such as 3 or, as here, infinite, so the element can bounce up and down forever (or until you get annoyed enough by the bouncing that you close the tab). See the full source code in ch09/animations-1.html.

In the next example, two properties are animated simultaneously—the element still bounces up and down, but it also gets bigger as it reaches the bottom of the bounce.

As mentioned earlier, a keyframe is just like a regular CSS rule: you can list as many properties as you need (although like transitions, not all properties are animatable). For this example, all that’s been added to the previous one is a scale transform; see the full source code in ch09/animations-2.html:

@keyframes bounce {
    from { top: 50px; transform: scale(1); }
    25% { top: 350px; transform: scale(1.25); }
    50% { top: 50px; transform: scale(1); }
    75% { top: 350px; transform: scale(1.25); }
    to {  top: 50px; transform: scale(1); }
}

Just like transitions, multiple animations can be applied simultaneously. Next, you see the element doing the same up-and-down bounce animation as before, but now it’s also sliding left to right.

See the complete example in listing ch09/animations-3.html.

Browser support

 
  12 14 4 6 8 9 10 11.1 11.5 5 5.1
Opacity
RGBA  
HSL/HSLA  
2D transforms  
3D transforms            
Transitions  
Animation          
Key:
• Complete or nearly complete support
Incomplete or alternative support
Little or no support

Opacity in IE8 and earlier

Although IE8 doesn’t support the CSS3 opacity property, it does support setting opacity through its nonstandard filter mechanism:

-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";

This CSS will make the element it’s applied to have an opacity value of 0.5.

Transforms, transitions, and animations in current browsers

All current browsers that have support for transforms, transitions, and animations require a vendor prefix to make things work. For transforms and transitions, this is the normal level of pain for using experimental CSS—each property has to be listed five times. Here’s a section of code from ch09/transition-delay-2.html:

-moz-transition-duration: 10s, 10s;
-webkit-transition-duration: 10s, 10s;
-o-transition-duration: 10s, 10s;
-ms-transition-duration: 10s, 10s;
transition-duration: 10s, 10s;
-moz-transition-delay: 0s, 10s;
-webkit-transition-delay: 0, 10s;
-o-transition-delay: 0, 10s;
-ms-transition-delay: 0, 10s;
transition-delay: 0, 10s;
-moz-transition-property: top, -moz-transform;
-webkit-transition-property: top, -webkit-transform;
-o-transition-property: top, -o-transform;
-ms-transition-property: top, -ms-transform;
transition-property: top, transform;

For animations, it’s more of a pain. Even if you’re only animating standard properties, you must specify the keyframes for every browser you want to target, not including the standard declaration:

@-moz-keyframes bounce {
    from { top: 50px; }
    25% { top: 350px; }
    50% { top: 50px; }
    75% { top: 350px; }
    to { top: 50px; }
}
@-webkit-keyframes bounce {
    from { top: 50px; }
    25% { top: 350px; }
    50% { top: 50px; }
    75% { top: 350px; }
    to { top: 50px; }
}
@-o-keyframes bounce {
    from { top: 50px; }
    25% { top: 350px; }
    50% { top: 50px; }
    75% { top: 350px; }
    to { top: 50px; }
}
@-ms-keyframes bounce {
    from { top: 50px; }
    25% { top: 350px; }
    50% { top: 50px; }
    75% { top: 350px; }
    to { top: 50px; }
}

Then the element itself needs all the animation-* properties for each browser:

#animateme {
    -moz-animation-duration: 20s;
    -moz-animation-name: bounce;
    -moz-animation-iteration-count: infinite;
    -webkit-animation-duration: 20s;
    -webkit-animation-name: bounce;
    -webkit-animation-iteration-count: infinite;
    -o-animation-duration: 20s;
    -o-animation-name: bounce;
    -o-animation-iteration-count: infinite;
    -ms-animation-duration: 20s;
    -ms-animation-name: bounce;
    -ms-animation-iteration-count: infinite;
}

Of course, you should add the standard properties to this listing as well. This will get really fun when the animation properties are standardized, but you want to use them to animate prefixed properties. For example, it’s not yet clear if gradients and animations will be standardized at the same time (or even if gradients will be animatable) but if animations get standardized first in browsers, you could end up writing code like this:

@keyframes swipe {
    from {
        -moz-linear-gradient(to right, #fff, #f00)
        -webkit-linear-gradient(left, #fff, #f00)
        -o-linear-gradient(to right, #fff, #f00)
        -ms-linear-gradient(to right, #fff, #f00)
        -linear-gradient(to right, #fff, #f00)
     }
    50% {
        -moz-linear-gradient(to right, #f00, #fff, #f00)
        -webkit-linear-gradient(left, #f00, #fff, #f00)
        -o-linear-gradient(to right, #f00, #fff, #f00)
        -ms-linear-gradient(to right, #f00, #fff, #f00)
        -linear-gradient(to right, #f00, #fff, #f00)
    }
    to {
        -moz-linear-gradient(to right, #f00, #fff)
        -webkit-linear-gradient(left, #f00, #fff)
        -o-linear-gradient(to right, #f00, #fff)
        -ms-linear-gradient(to right, #f00, #fff)
        -linear-gradient(to right, #f00, #fff)
    }
}

Using modernizr.js and jQuery for animation in older browsers

CSS Animations are intended to replace those implemented in libraries like jQuery. Using modernizr.js, it’s easy to detect whether a browser supports CSS Animations and, if it doesn’t, to supply equivalent jQuery animations instead. The following code is taken from ch09/animations-modernizr.html; it’s based on the earlier example ch09/animations-1.html:

Summary

You’re now fully prepared to produce Web 2.0–style designs with layers of semitransparent elements thanks to opacity and rgba(). You’re also fully equipped to create sets of complementary colors in your head thanks to hsl() and hsla(). Transforms and transitions create lots of possibilities for making user interfaces smoother and more professional.