Site icon Treehouse Blog

Using jQuery to Detect When CSS3 Animations and Transitions End

compass sprites

It seems like only a couple of years ago that almost every animation on a web page was done either by means of Flash or a JavaScript library like jQuery.

CSS3 has put that to rest. Simple, elegant animations are possible using CSS3 transitions, and even complex fine-grained movement can be accomplished using CSS3 keyframe animations. And now that every major modern browser supports both transitions and keyframe animations, they are a very real possibility on every new project we create.

In this post, I’ll discuss how you can include callback-like behaviour when using CSS3 transitions and animations, and thus keep your animation effects separate from your jQuery logic.

Separating Logic from Effect

How do we apply a principle like “separation of concerns” when implementing both JavaScript and CSS3? Although no solution works in every circumstance (i.e. the “it depends” adage applies here), I do believe we can lay down some practical guidelines in this area.

My advice up front in this post is: Use JavaScript for logic, functionality, and event firing, and use CSS3 for creating the effects (i.e. animations and/or transitions) that the JavaScript triggers.

In the past, when CSS3 animations weren’t an option, we would see jQuery code that resembled this:

$('#button').click(function () { 

    $('.box').animate({
        height: '300px',
        width: '200px'
    }, 3000);

});

A pretty bare-bones example, but it demonstrates the need for separation. The click event is indeed handled by the JavaScript, but we also have an animation with hard-coded CSS values in the JavaScript.

CSS3, however, lets us separate the functionality from the animation, so now our JavaScript might look like this:

$('#button').click(function () { 

    $('.box').toggleClass('change-size');

});

And here’s our associated CSS:

.box {
    /* vendor prefixes excluded for brevity */
    transition: width 3s linear,
                height 3s linear;
}

.change-size {
    width: 300px;
    height: 200px;
}

Here we’re using jQuery to add the specified class on the element that is supposed to animate. Then the animation itself is defined in the CSS, where it’s easier to deal with.

This might not work for every possible situation, but it accomplishes exactly what we want – it separates the logic from the effect, avoiding scripts that are littered with CSS value declarations.

Now that we understand that concept, let’s look at how we can use JavaScript to trigger actions when these CSS3 effects have completed.

Executing Code When Transitions End

One of the useful parts of changing CSS values using jQuery’s .animate method is the callback function that fires when the animation is complete. Unfortunately, jQuery’s addClass, removeClass, and .toggleClass methods (one of which is used in the code above) don’t include an option for a callback. Other jQuery methods might also have this limitation.

As an alternative, however, you can use JavaScript to detect when a transition on an element has completed. This way we can still have an optional callback-like effect.

Here’s how such code might look:

var myButton = $('#button'),
       myBox = $('#box');

myButton.click(function () { 

    myBox.toggleClass('change-size');

    myBox.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',   
    function(e) {

    // code to execute after transition ends

  });

});

You can view this code in action at this JS Bin. In that example, I’ve added an extra line that writes a message to the page each time the transition completes.

So what’s happening in the code? After caching our DOM elements, first we toggle the class name when the button is clicked. After that, we bind the transitionend event using jQuery’s .one method (vendor prefixes added for full compatibility, including two for Opera).

Next we run the part of the code that we want to execute after the end of the transition. The .one method (as opposed to .on()) is necessary to ensure that the code executes only once.

Executing Code When an Animation Ends

Now let’s try the same thing with a keyframe animation. Our CSS will have a chunk that looks like this:

.box {
    width: 100px;
    height: 100px;
    background: hotpink;
}

@keyframes growBox {

    to {
        width: 300px;
        height: 200px;
    }

}

.change-size {
    animation: growBox 3s linear 0s 1 normal;
}

Then, our JavaScript is as follows:

var myButton = $('#button'),
       myBox = $('#box');

myButton.click(function () { 

    myBox.addClass('change-size');
  
    myBox.one('webkitAnimationEnd oanimationend msAnimationEnd animationend',   
    function(e) {
    
    // code to execute after animation ends

    myBox.removeClass('change-size');
    });

});

You can view a working version of this code in this JSBin.

This code is very similar to the one we used for transitions. The differences are as follows: We’re using the animationend event in place of transitionend, and we’re adding and removing the “change-size” class, rather than toggling it.

Summary

In conclusion, here’s a summary of what I’ve covered here, and then some resources for further reading:

Further Reading

Exit mobile version