Fixing Common jQuery Animation Mistakes

I’ve seen people making the same mistake again and again when I’ve been helping on the jQuery IRC channel, and so I wanted to take the opportunity to write about it a bit to hopefully help clarify what the right way to handle the situation is. Basically, the trap people get themselves into is they want to fade in or out an element on the page, and then apply a CSS class to it. There is a right and a wrong way to do this.

So let’s consider the following markup:

<div id="myDiv">
    <img src="/image/path/to/myimage.jpg" />
</div

The goal is to have myDiv fade out when someone clicks on it, and then get the ‘hidden’ class applied to it. The hidden class has ‘display: none;’ in it as a CSS definition. Most beginner jQuery coders will do the following:

$("#myDiv").click(function() {
    $(this).fadeOut('slow');
    $(this).addClass('hidden');
});

While this looks like it would work, it really won’t. What will happen every time is the hidden class will get applied as soon as you click on it and they won’t see a fade happen. This is because while the fadeOut is occurring, the code moves along to the next statement, and applies the class. So, you click, and myDiv goes ‘poof’. The code does not pause at the fadeOut and wait for it to complete before moving on.

In order to get this to work properly, you need to use what is called a ‘callback’ function. This is a function which will be called once a process has completed. In this case, you want to wait for the fadeOut to complete before adding the class. Quoting the jQuery API docs:

If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments,
but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once
for the animation as a whole.

Here is the proper syntax to do that:

$("#myDiv").click(function() {
    $(this).fadeOut('slow', function() {
        $(this).addClass('hidden');
    });
}

This will behave the way you want. Using this method, the addClass will not fire until the fadeOut has completed. Thanks for reading, leave any comments below!

Published 22 Aug 2011

Writing better code by building better JavaScript
Don Burks on Twitter