Search code examples
javascriptjqueryanimationsliding

How do I stop a bouncy JQuery animation?


In a webapp I'm working on, I want to create some slider divs that will move up and down with mouseover & mouseout (respectively.) I currently have it implemented with JQuery's hover() function, by using animate() and reducing/increasing it's top css value as needed. This works fairly well, actually.

The problem is that it tends to get stuck. If you move the mouse over it (especially near the bottom), and quickly remove it, it will slide up & down continuously and won't stop until it's completed 3-5 cycles. To me, it seems that the issue might have to do with one animation starting before another is done (e.g. the two are trying to run, so they slide back and forth.)

Okay, now for the code. Here's the basic JQuery that I'm using:

$('.slider').hover(
    /* mouseover */
    function(){
        $(this).animate({
            top : '-=120'
        }, 300);
    },
    /* mouseout*/
    function(){
        $(this).animate({
            top : '+=120'
        }, 300);
    }
);

I've also recreated the behavior in a JSFiddle.

Any ideas on what's going on? :)

==EDIT== UPDATED JSFiddle


Solution

  • It isn't perfect, but adding .stop(true,true) will prevent most of what you are seeing.

    http://jsfiddle.net/W5EsJ/18/

    If you hover from bottom up quickly, it will still flicker because you are moving your mouse out of the div causing the mouseout event to fire, animating the div back down.

    You can lessen the flicker by reducing the delay, however it will still be present until the delay is 0 (no animation)

    Update

    I thought about it and realized that there is an obvious solution to this. Hoverintent-like functionality!

    http://jsfiddle.net/W5EsJ/20/

    $(document).ready(function() {
        var timer;
        $('.slider').hover(
            /* mouseover */
            function(){
                var self = this;
                timer = setTimeout(function(){
                    $(self).stop(true,true).animate({
                        top : '-=120'
                    }, 300).addClass('visible');
                },150)
            },
            /* mouseout*/
            function(){
                clearTimeout(timer);
                $(this).filter(".visible").stop(true,true).animate({
                    top : '+=120'
                }, 300).removeClass("visible");
            }
        );
    });