CSS transition from `display: none` on class change?

I've started using transitions to "modernise" the feel of a site. So far, :hover transitions are working great. Now I'm wondering if it's possible to trigger a transition based on other things, such as when a class changes.

Here's the relevant CSS:

#myelem {
    opacity: 0;
    display: none;
    transition: opacity 0.4s ease-in, display 0.4s step-end;
    -ms-transition: opacity 0.4s ease-in, display 0.4s step-end;
    -moz-transition: opacity 0.4s ease-in, display 0.4s step-end;
    -webkit-transition: opacity 0.4s ease-in, display 0.4s step-end;
}
#myelem.show {
    display: block;
    opacity: 1;
    transition: opacity 0.4s ease-out, display 0.4s step-start;
    -ms-transition: opacity 0.4s ease-out, display 0.4s step-start;
    -moz-transition: opacity 0.4s ease-out, display 0.4s step-start;
    -webkit-transition: opacity 0.4s ease-out, display 0.4s step-start;
}

The JavaScript to trigger the change is:

document.getElementById('myelem').className = "show";

But the transition doesn't seem to be happening - it's just jumping from one state to the other.

What am I doing wrong?


It does work when you remove the display properties.

#myelem {
    opacity: 0;
    transition: opacity 0.4s ease-in;
    -ms-transition: opacity 0.4s ease-in;
    -moz-transition: opacity 0.4s ease-in;
    -webkit-transition: opacity 0.4s ease-in;
}
#myelem.show {
    opacity: 1;
    transition: opacity 0.4s ease-out;
    -ms-transition: opacity 0.4s ease-out;
    -moz-transition: opacity 0.4s ease-out;
    -webkit-transition: opacity 0.4s ease-out;
}​

JSFiddle.

The reason for this is that only CSS properties with numbers can be transitioned. What do you think the "50% state" should be between "display: none;" and "display: block;"? Since that can't be calculated, you can't animate the display property.


You cannot use the display property for transitioning between states.


The answer provided by @MarcoK including the comments shows already the right direction. Setting display property hinders transition.
A better practice is though to put the unprefixed (standards) version after the browser-vendor prefixed ones, in order to be future-proof. The latter properties overwrite the former.
Other improvements:

  • As @Charmander pointed out, -ms-transition isn't supported by any Internet Explorer
  • There's also Opera's vendor prefixed -o-transition for Op 10.5-12 & Op Mobile 10-12, which currently is probably supported by less than .1% of global browser. I'll put it in for completion

CSS:

#myelem {
    opacity: 0;
    -webkit-transition: opacity .4s ease-in;
       -moz-transition: opacity .4s ease-in;
         -o-transition: opacity .4s ease-in;
            transition: opacity .4s ease-in;
}
#myelem.show {
    opacity: 1;
    -webkit-transition: opacity .4s ease-out;
       -moz-transition: opacity .4s ease-out;
         -o-transition: opacity .4s ease-out;
            transition: opacity .4s ease-out;
}​