thinking stiff

CSS transitions with Javascript

Posted in Programming by thinkingstiff on 2013/02/08

Assigning CSS transitions in Javascript can be tricky due to both order of assignment and timing. Stepping though while debugging can give you different results than running live, which makes it difficult to find the problem. In answering CSS transitions do not work when assigned trough JavaScript on Stackoverflow, I came up with the following guidelines.

To make transition work, three things have to happen.

1. the element has to have the property explicitly defined (ex: opacity: 0;)
2. the element must have the transition defined: transition: opacity 2s;
3. the new property must be set: opacity: 1

If you are assigning #1 and #2 dynamically, there needs to be a delay before #3 so the browser can process the request. If you are debugging, it will often appear to work because you are creating this delay by stepping through it, giving the browser time to process. Adding transition to an element is not what triggers the animation, changing the property does.

To create this delay you can either add the first two steps to the HTML at design time, or create the delay in Javascript with .setTimeout().

Demo: http://jsfiddle.net/ThinkingStiff/QNnnQ/

HTML:

    <div id="fade1" class="fadeable">fade 1 - works</div>
    <div id="fade2">fade 2 - doesn't work</div>
    <div id="fade3">fade 3 - works</div>

CSS:

    .fadeable {
        opacity: 0;
    }
    
    .fade-in {
        opacity: 1;
        transition:             opacity 2s;
            -moz-transition:    opacity 2s;
            -ms-transition:     opacity 2s;
            -o-transition:      opacity 2s;
            -webkit-transition: opacity 2s;
    }

Script:

    //works
    document.getElementById( 'fade1' ).className += ' fade-in';
    
    //doesn't work
    document.getElementById( 'fade2' ).className = 'fadeable';
    document.getElementById( 'fade2' ).className += ' fade-in';
    
    //works
    document.getElementById( 'fade3' ).className = 'fadeable';
    window.setTimeout( function() {
        
        document.getElementById( 'fade3' ).className += ' fade-in';
        
    }, 100);