views:

521

answers:

1

Hi,

I'm trying to do a simple animation.

  1. You show the div. It animates correctly.
  2. You hide the div. Correct.
  3. You show the div again. It shows but there is no animation. It is stuck at the value of when you first interrupted it.

So somehow the interpolation CSS that is happening during [add|remove]Class is getting stuck there. The second time around, the [add|remove]Class is actually running, but the css it's setting from the class is getting ignored (I think being overshadowed). How can I fix this WITHOUT resorting to .animate and hard-coded style values? The whole point was to put the animation end point in a css class.

Thanks!

<!doctype html>

<style type="text/css">
div {
    width: 400px;
    height: 200px;
}
.green {
    background-color: green;
}
</style>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
    $('#show').bind({
        click: function() {
            showAndRun()
        }
    })
    $('#hide').bind({
        click: function() {
            $('div').stop(true, false).fadeOut('slow')
        }
    })

    function showAndRun() {
        function pulse() {
            $('div').removeClass('green', 2000, function() {
                $(this).addClass('green', 2000, pulse)
            })
        }
        $('div').stop(true, false).hide().addClass('green').fadeIn('slow', pulse)
    }
})
</script>

<input id="show" type="button" value="show" /><input id="hide" type="button" value="hide" />
<div style="display: none;"></div>

You can also look at what it does here at jsbin

A: 

I figured out the solution. Not sure if I'm happy with it yet though. It's essentially a very poor "reset" of the CSS when show is clicked

The animation loops forever. So I can't rely on a jQuery queue (finite length). I have to achieve the loop via the callback as shown in the code. The problem that causes: you can't .stop(true, true) . The first true clears the queue, but there is nothing in the queue after the animation that is currently running. So that's useless. The second true jumps to the last animation in the queue. Again useless, since we're actually going to be staying in the one thing that is looping on itself. The 2nd arg must be false to interrupt the, otherwise, infinite loop.

The problem with interruption. It leaves the css where it is. You are now stuck with random css props on whatever it was that your animation was interpolating over (in my case the background-color). Also I wanted the interruption to be instant. So there was no other way.

In my case, the background-color during the animation was being set on element.style (discovered by inspection in browser tools), which overrides anything else that's going on. This prop did not exist until the first animation had started running. Then it got interrupted and the supposed-to-be-temporary style got stuck there (I guess).

So you run the animation again. The green class is applied. jQuery figures out the range of colors to progress through. Turns out its from #shadeofgreen to #thesameshadeofgreen, because the stuck element.styles value overrides anything provided by the class. So the animation slides between two of the same color. It's running! But there's no color to change to.

So the fix in my case isn't horrible, but I'm still not sure I like it, because I'm not sure it could be easily applied to a variety of situations.

Change

$('div').stop(true, false).hide().addClass('green').fadeIn('slow', pulse)

to

$('div').stop(true, false).removeAttr('style').hide().addClass('green').fadeIn('slow', pulse)

The key is the

.removeAttr('style').hide().addClass('green')

That is essentially your css reset. Guaranteed to always be there when you need it since it's happening exactly before the thing will get displayed again.

Note that putting !important on the color in the green css class, doesn't work, because that (seems to) will override element.styles (which the jQuery animation uses), and you will not get the desired result.

Of course I am still open to suggestions. I probably missed something since I only started looking at CSS and jQuery at the top of the week.

You can see the effects of the .removeAttr('style') in the fixed code here on jsbin.

Jason D