Animar scrollTop no funciona en Firefox
Esta función funciona bien. Desplaza el cuerpo hasta el desplazamiento del contenedor deseado.
function scrolear(destino){
var stop = $(destino).offset().top;
var delay = 1000;
$('body').animate({scrollTop: stop}, delay);
return false;
}
Pero no en Firefox. ¿Por qué?
-EDITAR-
Para manejar el doble disparador en la respuesta aceptada, sugiero detener el elemento antes de la animación:
$('body,html').stop(true,true).animate({scrollTop: stop}, delay);
Firefox coloca el desbordamiento en el html
nivel, a menos que tenga un estilo específico para comportarse de manera diferente.
Para que funcione en Firefox, use
$('body,html').animate( ... );
Ejemplo de trabajo
La solución CSS sería establecer los siguientes estilos:
html { overflow: hidden; height: 100%; }
body { overflow: auto; height: 100%; }
Supongo que la solución JS sería la menos invasiva.
Actualizar
Gran parte de la discusión a continuación se centra en el hecho de que animar scrollTop
dos elementos provocaría que la devolución de llamada se invocara dos veces. Se han sugerido funciones de detección del navegador que posteriormente han quedado obsoletas, y podría decirse que algunas son bastante descabelladas.
Si la devolución de llamada es idempotente y no requiere mucha potencia informática, activarla dos veces puede no ser un problema. Si múltiples invocaciones de la devolución de llamada son realmente un problema, y si desea evitar la detección de funciones, podría ser más sencillo exigir que la devolución de llamada solo se ejecute una vez desde dentro de la devolución de llamada:
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');
}));
Sería bueno detectar características y luego animar en un único objeto compatible, pero no existe una solución de una sola línea. Mientras tanto, aquí se muestra una forma de utilizar una promesa para realizar una única devolución de llamada por ejecución.
$('html, body')
.animate({ scrollTop: 100 })
.promise()
.then(function(){
// callback code here
})
});
ACTUALIZACIÓN: Así es como puede utilizar la detección de funciones. Este fragmento de código debe evaluarse antes de la llamada de la animación:
// Note that the DOM needs to be loaded first,
// or else document.body will be undefined
function 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();
Ahora use la var que acabamos de definir como selector para la animación de desplazamiento de la página y use la sintaxis normal:
$(scrollTopElement).animate({ scrollTop: 100 }, 500, function() {
// normal callback
});
Pasé años intentando descubrir por qué mi código no funcionaba.
$('body,html').animate({scrollTop: 50}, 500);
El problema estaba en mi CSS.
body { height: 100%};
Lo configuré en auto
su lugar (y me quedé preocupándome por qué estaba configurado 100%
en primer lugar). Eso me solucionó.