21

I'm trying to animate a dynamically created html element with CSS3 transitions.

I want the animation to start just before the element is created.
For these i create a class that set the original position of the element and then I set the target position by the jquery css() method

But the new element it just apears in the target position without any transition.

If I use a setTimeout of 0ms to set the new css value it work.

There is something I'm doing wrong? or is a limitation? I don't think I should need to use the setTimeout workaround.

Thanks!

UPDATE: Here is a link with the code running on jsfiddle.net for you to experiment. http://jsfiddle.net/blackjid/s9zSH/

UPDATE I've updated the example with the solution in the answer.
http://jsfiddle.net/s9zSH/52/

Here is a fully working example code

<html>
    <head>
        <script src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
        <script type="text/javascript">

        //Bind click event to the button to duplicate the element
        $(".duplicate").live("click", function (e){
            var $to = $("#original .square").clone()
            $("body").append($to);
            if($(e.target).hasClass("timeout"))
                //With setTimeout it work
                setTimeout(function() {
                    $to.css("left", 200 + "px");
                },0);
            else if($(e.target).hasClass("notimeout"))
                // These way it doesn't work
                $to.css("left", 200 + "px");
        });

        </script>
        <style type="text/css">
        .animate{
            -webkit-transition: all 1s ease-in;
        }
        .square{
            width:50px;
            height:50px;
            background:red;
            position:relative;
            left:5px;
        }
        </style>
    </head>
    <body>
        <div id="original">
            <div class="square animate"></div>
        </div>

        <button class="duplicate timeout">duplicate with setTimeout</button>
        <button class="duplicate notimeout">duplicate without setTimeout</button>
    </body>
</html>
blackjid
  • 1,571
  • 16
  • 23

1 Answers1

22

You don't need to use a timeout. Timeout works because the page is reflowed between setting styles. Reflowing recalculates the styles.If you don't recalculate the styles, the second style simply overwrites the first. That's the real issue.

Rather, you can simply:

obj.className = style1;
window.getComputedStyle(obj).getPropertyValue("top");
obj.className = style2;

If you're animating multiple objects, you only need to "pump" the style calculator once:

obj.className = style1;
obj2.className = style1;
obj3.className = style1;
window.getComputedStyle(obj).getPropertyValue("top");

obj.className = style2;
obj2.className = style2;
obj3.className = style2;

Tested in chrome12 on mac

mmaclaurin
  • 1,412
  • 1
  • 13
  • 18
  • 1
    addendum: while you don't have to use timeout, sometimes it can be good. it really depends on your application. forcing synchronous recalculation of styles, if done frequently, can make your UI stutter. if you find that happening, use timeout judiciously to break up/amortize a complex animation over a few frames. – mmaclaurin Jun 19 '12 at 20:34
  • Thank you, this is the first explanation I've found of *why* a setTimeout is effective for forcing CSS transitions. – B. Striegel May 07 '13 at 16:19
  • Wow, great! You saved my day. Wasted quite a lot time to find out the reason, finally you solved it. thanks again! – Cam Song Sep 03 '14 at 15:20