Fading in via CSS transition doesn't work properly

Problem

I'm trying to animate a page element using CSS transition on opacity property. Fading out works properly, but Fading in doesn't. What am I doing wrong?

Some facts are really strange:

  • Without using .no-display class everything works as expected (but I should use it).
  • Replaying function's commands in browser console does work as expected (but function does not).

The code:

HTML

<p><a href="javascript:fadeIn()">Fade in</a></p>
<p><a href="javascript:fadeOut()">Fade out</a></p>
<div class="no-display invisible" id="square"></div>

CSS

.no-display {
    display: none;
}

.invisible {
    opacity: 0;
}

#square {
    width: 500px;
    height: 500px;
    background-color: red;
    border: 1px solid black;

    -webkit-transition: opacity 2s ease;
    -moz-transition: opacity 2s ease;
    -ms-transition: opacity 2s ease;
    -o-transition: opacity 2s ease;
    transition: opacity 2s ease;
}

JavaScript

function fadeIn() {
    square.classList.remove("no-display");
    square.classList.remove("invisible");
}

function fadeOut() { 
    square.classList.add("invisible");
    setTimeout(function() { square.classList.add("no-display"); }, 2000 );
}

Or: http://jsfiddle.net/V2Sar/6/.

Note, I can't use any frameworks such as jQuery. I have to work only with pure JavaScript.

Problem courtesy of: Ivan Akulov

Solution

The easy way to trigger CSS transitions with JS is to toggle classnames, and the easy way to do that is through the classList API.

js

var square = document.getElementById("square");
function fadeIn() {
    square.classList.remove("invisible");
}

function fadeOut() { 
    square.classList.add("invisible");
}

css

#square {
    opacity: 1;
    transition: opacity 2s ease;
}
#square.invisible {
    opacity: 0;
}

http://jsfiddle.net/V2Sar/5/

Also, make sure your scripts are at the end of the <body> so you don't need to worry about whether the DOM is constructed yet (separate option in jsfiddle for this).

The browser support isn't great (no support in IE9) but there is a shim available at https://github.com/eligrey/classList.js

Let me know if this isn't good enough for you and I'll post some alternatives as well.

Solution courtesy of: xec

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.