Animate scrollTop not working in firefox

Toni Michel Caubet picture Toni Michel Caubet · Nov 16, 2011 · Viewed 95.1k times · Source

This function works fine. It scrolls the body to a desired container's offset

function scrolear(destino){
    var stop = $(destino).offset().top;
    var delay = 1000;
    $('body').animate({scrollTop: stop}, delay);
    return false;
}

But not in Firefox. Why?

-EDIT-

To handle de double trigger in the accepted answer, I suggest stoping the element before the animation:

$('body,html').stop(true,true).animate({scrollTop: stop}, delay);

Answer

David Hedlund picture David Hedlund · Nov 16, 2011

Firefox places the overflow at the html level, unless specifically styled to behave differently.

To get it to work in Firefox, use

$('body,html').animate( ... );

Working example

The CSS solution would be to set the following styles:

html { overflow: hidden; height: 100%; }
body { overflow: auto; height: 100%; }

I would assume that the JS solution would be least invasive.


Update

A lot of the discussion below focuses on the fact that animating the scrollTop of two elements would cause the callback to be invoked twice. Browser-detection features have been suggested and subsequently deprecated, and some are arguably rather far-fetched.

If the callback is idempotent and doesn't require a lot of computing power, firing it twice may be a complete non-issue. If multiple invocations of the callback are truly an issue, and if you want to avoid feature-detection, it might be more straight-forward to enforce that the callback is only run once from within the callback:

function runOnce(fn) { 
    var count = 0; 
    return function() { 
        if(++count == 1)
            fn.apply(this, arguments);
    };
};

$('body, html').animate({ scrollTop: stop }, delay, runOnce(function() {
   console.log('scroll complete');
}));