¿Es posible animar scrollTop con jQuery?

226

Quiero desplazarme suavemente hacia abajo. No quiero tener que escribir una función para eso, especialmente si jQuery ya tiene una.

Bryan Field
fuente

Respuestas:

463

Simplemente puede usar .animate()la scrollToppropiedad, así:

$("html, body").animate({ scrollTop: "300px" });
Nick Craver
fuente
Muy bien ... no es necesario usar complementos para esto.
Amol M Kulkarni
15
¿Por qué necesitas ambos htmly body? Aquí hay una idea: stackoverflow.com/questions/2123690/… , pero no es una respuesta completa.
Haralan Dobrev
28
webkit usa el cuerpo, firefox usa html.
Jory
2
FYI: Si <html>tiene overflow-x:hidden;este animado no funcionará. (No podría funcionar para overflow-y:hiddeny overflow:hidden, pero no lo he probado.
collinhaines
1
Creo que bodyfuncionó en Chrome a principios de este año, pero ahora tiene que ser así html.
Nick Davies
73

La respuesta de Nick funciona muy bien. Tenga cuidado al especificar una función complete () dentro de la llamada animate () porque se ejecutará dos veces ya que tiene dos selectores declarados (html y body).

$("html, body").animate(
    { scrollTop: "300px" },
    {
        complete : function(){
            alert('this alert will popup twice');
        }
    }
);

Así es como puede evitar la doble devolución de llamada.

var completeCalled = false;
$("html, body").animate(
    { scrollTop: "300px" },
    {
        complete : function(){
            if(!completeCalled){
                completeCalled = true;
                alert('this alert will popup once');
            }
        }
    }
);
Kita
fuente
1
La pregunta es, ¿por qué animarías 'html, body' y no solo 'body'?
Lior
21
Porque dependiendo del navegador que sea, puede animar el cuerpo O html. Al animar AMBOS, cubres más navegadores.
Bene
Pero en este caso, aparecerá solo una vez, también si tiene que ser llamado repetidamente (haga clic en el evento en el botón) o me falta algo.
HoGo
Sí, en este caso solo aparecerá una vez. Si necesita animar repetidamente, haría que la variable completeCalled sea local para la función de devolución de llamada que ejecuta la función de animación. De esa manera, solo aparecerá una vez cuando haga clic, pero volverá a aparecer (solo una vez) cuando vuelva a hacer clic.
Kita
Para evitar el disparo de la función de devolución de llamada doble, puede usar la die()función antes de la live()llamada de función. Esto garantiza que su live()controlador se llamará solo una vez.
Lord Nighton
27

La respuesta de Nick funciona muy bien y la configuración predeterminada es buena, pero puedes controlar más completamente el desplazamiento completando todas las configuraciones opcionales.

así es como se ve en la API:

.animate( properties [, duration] [, easing] [, complete] )

para que puedas hacer algo como esto:

.animate( 
    {scrollTop:'300px'},
    300,
    swing,
    function(){ 
       alert(animation complete! - your custom code here!); 
       } 
    )

Aquí está la página API de la función jQuery .animate: http://api.jquery.com/animate/

pionero
fuente
15

Como mencionó Kita, hay un problema con la activación de múltiples devoluciones de llamada cuando se anima tanto en 'html' como en 'body'. En lugar de animar a ambos y bloquear las devoluciones de llamadas posteriores, prefiero usar alguna detección de funciones básicas y solo animar la propiedad scrollTop de un solo objeto.

La respuesta aceptada en este otro hilo da una idea de qué propiedad scrollTop del objeto deberíamos intentar animar: pageYOffset Scrolling and Animation en IE8

// UPDATE: don't use this... see below
// only use 'body' for IE8 and below
var scrollTopElement = (window.pageYOffset != null) ? 'html' : 'body';

// only animate on one element so our callback only fires once!
$(scrollTopElement).animate({ 
        scrollTop: '400px' // vertical position on the page
    },
    500, // the duration of the animation 
    function() {       
        // callback goes here...
    })
});

ACTUALIZACIÓN - - -

El intento anterior de detección de características falla. Parece que no hay una forma de una línea de hacerlo como página de navegadores de tipo webkit La propiedad Offset siempre devuelve cero cuando hay un doctype. En cambio, encontré una manera de usar una promesa de hacer una única devolución de llamada cada vez que se ejecuta la animación.

$('html, body')
    .animate({ scrollTop: 100 })
    .promise()
    .then(function(){
        // callback code here
    })
});
Stephen
fuente
1
Usar Promesa () aquí es genial.
Allan Bazinet
Esto necesita más votos a favor. Nunca he visto una promesa utilizada para esto antes, y esto es algo que termino buscando cada pocos meses. Como dijo Allan, genio.
Tortilaman
14

Tengo lo que creo que es una mejor solución que el $('html, body')hack.

No es una línea, pero el problema que tuve $('html, body')es que si inicias sesión $(window).scrollTop()durante la animación, verás que el valor salta por todas partes, a veces por cientos de píxeles (aunque no veo nada de eso sucediendo visualmente). Necesitaba que el valor fuera predecible, para poder cancelar la animación si el usuario agarraba la barra de desplazamiento o giraba la rueda del mouse durante el desplazamiento automático.

Aquí hay una función que animará el desplazamiento sin problemas:

function animateScrollTop(target, duration) {
    duration = duration || 16;
    var scrollTopProxy = { value: $(window).scrollTop() };
    if (scrollTopProxy.value != target) {
        $(scrollTopProxy).animate(
            { value: target }, 
            { duration: duration, step: function (stepValue) {
                var rounded = Math.round(stepValue);
                $(window).scrollTop(rounded);
            }
        });
    }
}

A continuación se muestra una versión más compleja que cancelará la animación sobre la interacción del usuario, así como también se recargará hasta alcanzar el valor objetivo, lo cual es útil cuando se intenta configurar el scrollTop instantáneamente (por ejemplo, simplemente llamando $(window).scrollTop(1000), en mi experiencia, esto no funciona. 50% del tiempo)

function animateScrollTop(target, duration) {
    duration = duration || 16;

    var $window = $(window);
    var scrollTopProxy = { value: $window.scrollTop() };
    var expectedScrollTop = scrollTopProxy.value;

    if (scrollTopProxy.value != target) {
        $(scrollTopProxy).animate(
            { value: target },
            {
                duration: duration,

                step: function (stepValue) {
                    var roundedValue = Math.round(stepValue);
                    if ($window.scrollTop() !== expectedScrollTop) {
                        // The user has tried to scroll the page
                        $(scrollTopProxy).stop();
                    }
                    $window.scrollTop(roundedValue);
                    expectedScrollTop = roundedValue;
                },

                complete: function () {
                    if ($window.scrollTop() != target) {
                        setTimeout(function () {
                            animateScrollTop(target);
                        }, 16);
                    }
                }
            }
        );
    }
}
John Starr Dewar
fuente
7

Tenía problemas donde la animación siempre comenzaba desde la parte superior de la página después de una actualización de la página en los otros ejemplos.

Solucioné esto no animando el CSS directamente, sino llamando window.scrollTo();a cada paso:

$({myScrollTop:window.pageYOffset}).animate({myScrollTop:300}, {
  duration: 600,
  easing: 'swing',
  step: function(val) {
    window.scrollTo(0, val);
  }
});

Esto también evita el problema de htmlvs body, ya que está usando JavaScript entre navegadores.

Eche un vistazo a http://james.padolsey.com/javascript/fun-with-jquerys-animate/ para obtener más información sobre lo que puede hacer con la función animada de jQuery.

cómplice
fuente
5

Puede usar la animación jQuery para la página de desplazamiento con una duración específica:

$("html, body").animate({scrollTop: "1024px"}, 5000);

donde 1024px es el desplazamiento de desplazamiento y 5000 es la duración de las animaciones en milisegundos.

Alessandro Pirovano
fuente
¡Gran respuesta! Me alegra que hayas incluido la opción de duración. Solo quería agregar que $("html, body").animate({scrollTop: 1024}, 5000);también funciona.
Ryan Taylor
4

Pruebe el complemento scrollTo .

Tatu Ulmanen
fuente
Parece que scrollTo ya no es un proyecto en ese sitio.
Jim
El código para lograr esto es muy simple. ¿Por qué agregaría un complemento para hacer algo que puede hacer con una línea de código?
Gavin
44
Hace cuatro años no era tan simple .. :)
Tatu Ulmanen
4
$(".scroll-top").on("click", function(e){
   e.preventDefault();
   $("html, body").animate({scrollTop:"0"},600);
});
Rubel Hossain
fuente
1

Si desea desplazarse hacia abajo al final de la página (por lo que no necesita desplazarse hacia abajo), puede usar:

$('body').animate({ scrollTop: $(document).height() });
Hormiga pequeña
fuente
0

Pero si realmente desea agregar algo de animación mientras se desplaza, puede probar mi complemento simple ( AnimateScroll ) que actualmente admite más de 30 estilos de suavizado

Ram Patra
fuente
-3

el código del navegador cruzado es:

$(window).scrollTop(300); 

no tiene animación pero funciona en todas partes

usuario2760861
fuente
66
Estaba buscando una manera de "animar scrollTop con jQuery?" Una respuesta que es "sin animación" no es una respuesta.
Bryan Field