Animate scrollTop not working in firefox Animate scrollTop not working in firefox jquery jquery

Animate scrollTop not working in firefox


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');}));


Feature detection and then animating on a single supported object would be nice, but there's not a one line solution. In the meantime, here's a way to use a promise to do a single callback per execution.

$('html, body')    .animate({ scrollTop: 100 })    .promise()    .then(function(){        // callback code here    })});

UPDATE:Here's how you could use feature detection instead. This chunk of code needs to get evaluated before your animation call:

// Note that the DOM needs to be loaded first, // or else document.body will be undefinedfunction getScrollTopElement() {    // if missing doctype (quirks mode) then will always use 'body'    if ( document.compatMode !== 'CSS1Compat' ) return 'body';    // if there's a doctype (and your page should)    // most browsers will support the scrollTop property on EITHER html OR body    // we'll have to do a quick test to detect which one...    var html = document.documentElement;    var body = document.body;    // get our starting position.     // pageYOffset works for all browsers except IE8 and below    var startingY = window.pageYOffset || body.scrollTop || html.scrollTop;    // scroll the window down by 1px (scrollTo works in all browsers)    var newY = startingY + 1;    window.scrollTo(0, newY);    // And check which property changed    // FF and IE use only html. Safari uses only body.    // Chrome has values for both, but says     // body.scrollTop is deprecated when in Strict mode.,    // so let's check for html first.    var element = ( html.scrollTop === newY ) ? 'html' : 'body';    // now reset back to the starting position    window.scrollTo(0, startingY);    return element;}// store the element selector name in a global var -// we'll use this as the selector for our page scrolling animation.scrollTopElement = getScrollTopElement();

Now use the var that we just defined as the selector for the page scrolling animation, and use the regular syntax:

$(scrollTopElement).animate({ scrollTop: 100 }, 500, function() {    // normal callback});


I spent ages trying to work out why my code wouldn't work -

$('body,html').animate({scrollTop: 50}, 500);

The problem was in my css -

body { height: 100%};

I set it to auto instead (and was left worrying about why it was set to 100% in the first place). That fixed it for me.