CodeinWP CodeinWP

The Subtleties of CSS3 Transitions

If you haven’t yet used CSS3 transitions extensively, here’s something you may not have picked up on.

As I’ve outlined before, transitions can be triggered in a number of ways, and even via JavaScript. The reason for this is because the actual transition is not dependent on any particular event. Although it is the event that triggers the transition, the transition itself is completely separate from the event (as it should be).

Because of this, you’ll notice a slightly quirky behaviour if you place the transition on the part of your CSS that triggers the event.

To illustrate this, here’s some simple transition code using the :hover pseudo-class:

a:link, a:visited {
  font-size: 40px;
  -webkit-transition: font-size 1s ease;
  -moz-transition: font-size 1s ease;
  -o-transition: font-size 1s ease;
  transition: font-size 1s ease;
}

a:hover {
  font-size: 100px;
}

And here’s a JSBin demo:

It’s pretty simple, right? You hover over the link, and the font-size animates (or transitions) from 40px to 100px. You hover off the link, and it transitions from 100px down to 40px.

Now let’s try it like this:

a:link, a:visited {
  font-size: 40px;
}

a:hover {
  font-size: 100px;
  -webkit-transition: font-size 1s ease;
  -moz-transition: font-size 1s ease;
  -o-transition: font-size 1s ease;
  transition: font-size 1s ease;
}

What’s different? Well, instead of placing the transition property on the natural link state, I’ve placed the transition on the hover state. And the result?

Maybe you’ve figured it out, but here’s the demo:

Since the transition is put directly on the hover state, now the transition only occurs on that state (that is, when the hover occurs). When you roll back off the link (which means the normal state is now occurring), the property changes instantly from 100px to 40px (as would normally happen, without a transition).

It’s a pretty small thing, but something to keep in mind if you’re placing your transitions on the event states rather than on the natural state of the element. I suppose there could be some isolated cases where you desire this behaviour so it might be good to know this subtle difference in transition behaviour.

A Possible Use Case

After the first comment posted by Jono below, I realized there’s a very good use for this difference. You can have the hover transition occur over a longer time than the hover off. Here’s the code:

a:link, a:visited {
  font-size: 40px;
  -webkit-transition: font-size 1s ease;
  -moz-transition: font-size 1s ease;
  -o-transition: font-size 1s ease;
  transition: font-size 1s ease;
}

a:hover {
  font-size: 100px;
  -webkit-transition: font-size 3s ease;
  -moz-transition: font-size 3s ease;
  -o-transition: font-size 3s ease;
  transition: font-size 3s ease;
}

And here’s the demo:

In that example, the hover-on transition would take 3 seconds, but the hover-off transition would take only 1 second (by changing the transition duration part of the shorthand code). There are probably tons of ways this could come in handy, because often it’s the user-enabled part of the transition you want to occur more obviously, whereas the “back to normal” transition would be fine if it occurred less obviously (i.e. in less time).

What it Means

This is why transitions work in conjunction with media queries (something I incorporated into my recent redesign). The transition has nothing to do with any media query; the transition properties are declared on the static states of the elements being transitioned. But when the media query changes the state of those properties, they animate rather than occur instantly.

This (at least for me) drives home the point of how transitions work. The transition, when placed on the static element state (as in the first example above), is telling the browser to animate the properties in question anytime that state is reached. Whenever the value of the assigned properties changes (no matter how they’ve changed), when they come back down (or up) to their original state, they should do so in an animated (not instantaneous) manner.

13 Responses

  1. Jono says:

    What happens when the transition is added to both the element and the element’s state? Does the cascade honor the state’s transition (overriding the element’s transition), or apply the element’s transition on :hover and the the state’s transition on mouse out?

    It would be nice to be able to set different transitions for :hover and deHover (mouseOut), without JavaScript.

  2. Chris Coyier says:

    Definitely the thing to know here is changing the transition for hover on / hover off (see also). Changing the duration can be a really nice effect, and in fact, I think it’s really common that having the transition occur quickly on the hover and slowly on the hover off looks better than having them the same duration. I almost wish we could do that without so much repetition, like just an additional property. transistion-duration-on / transition-duration-off (or something)

  3. Jim S. says:

    Thanks for the post. I haven’t used transitions yet, so this saved me some time figuring out what elements they need to be added to and how. The comments are thought provoking too.

  4. Emma says:

    Hi, thanks for this. Seems like a really simple bit of CSS. Great demos to to show how to get to grips with transitions. Can’t wait to have a play with this.

  5. patrick h. lauke says:

    The vendor prefix for Opera also needs the dash in front, btw… so -o-transition throughout all your examples ;)

  6. Ary Wibowo says:

    Thanks for the explanation of CSS3 Transitions. it very useful for me.

  7. Larry says:

    In my normalize.css (from h5bp) I apply a 100ms transition for colour on all my links – similar to how you’ve set them up on your current design.

    What I then do is remove the transition on all :active’s, that way ensuring that the UX when clicking is consistent with the on / off state of a mouse click. I get an unsettling feeling of, “OMG why is the link taking so long to react,” when the transition on the active is not removed.

    
    a {
    	color: #000;
    	text-decoration: none;
    	transition: color 100ms ease-in;
    }
    a:visited {}
    a:hover { color: #999;}
    a:active {
    	color: #666;
    	transition: color 0s;
    }
    

    I was happy to discover transitions can be made specific to different states, it helps with the user experience just that extra bit.

    Cool post :)

  8. Joe says:

    Elegant and useful CSS snippet, will be trying this and letting you know how I get on

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).