225 votes

Est-il possible d'animer scrollTop avec jQuery ?

Je veux pouvoir faire défiler les pages en douceur. Je ne veux pas avoir à écrire une fonction pour cela - surtout si jQuery en a déjà une.

462voto

Nick Craver Points 313913

Vous pouvez simplement utiliser .animate() le site scrollTop comme ceci :

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

73voto

Kita Points 582

La réponse de Nick fonctionne très bien. Faites attention lorsque vous spécifiez une fonction complete() à l'intérieur de l'appel animate() car elle sera exécutée deux fois puisque vous avez déclaré deux sélecteurs (html et body).

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

Voici comment vous pouvez éviter le double rappel.

var completeCalled = false;
$("html, body").animate(
    { scrollTop: "300px" },
    {
        complete : function(){
            if(!completeCalled){
                completeCalled = true;
                alert('this alert will popup once');
            }
        }
    }
);

26voto

pathfinder Points 859

La réponse de Nick fonctionne très bien et les paramètres par défaut sont agréables, mais vous pouvez mieux contrôler le défilement en complétant tous les paramètres optionnels.

Voici à quoi cela ressemble dans l'API :

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

donc vous pourriez faire quelque chose comme ça :

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

voici la page d'api de la fonction jQuery .animate : http://api.jquery.com/animate/

15voto

Stephen Points 61

Comme Kita l'a mentionné, il y a un problème avec le déclenchement de plusieurs callbacks lorsque vous animez à la fois "html" et "body". Au lieu d'animer les deux et de bloquer les rappels suivants, je préfère utiliser une détection de base des caractéristiques et n'animer que la propriété scrollTop d'un seul objet.

La réponse acceptée sur cet autre fil de discussion donne un aperçu de la propriété scrollTop de l'objet que nous devons essayer d'animer : Défilement et animation de la pageYOffset dans 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...
    })
});

MISE À JOUR - - -

La tentative ci-dessus de détection des caractéristiques échoue. Il semble qu'il n'y ait pas de moyen unique de le faire, car la propriété pageYOffset des navigateurs de type webkit renvoie toujours zéro lorsqu'il y a un doctype. Au lieu de cela, j'ai trouvé un moyen d'utiliser une promesse pour faire un seul callback pour chaque fois que l'animation s'exécute.

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

14voto

John Starr Dewar Points 701

J'ai ce que je crois être une meilleure solution que la $('html, body') pirate.

Ce n'est pas une phrase toute faite, mais le problème que j'avais avec $('html, body') est que si vous vous connectez $(window).scrollTop() Pendant l'animation, vous verrez que la valeur saute partout, parfois de plusieurs centaines de pixels (bien que je ne voie rien de tel visuellement). J'avais besoin que la valeur soit prévisible, afin de pouvoir annuler l'animation si l'utilisateur saisit la barre de défilement ou fait tourner la molette de la souris pendant le défilement automatique.

Voici une fonction qui animera le défilement en douceur :

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

Vous trouverez ci-dessous une version plus complexe qui annulera l'animation en cas d'interaction avec l'utilisateur, et qui la réactivera jusqu'à ce que la valeur cible soit atteinte, ce qui est utile lorsque vous essayez de définir le scrollTop instantanément (par exemple, en appelant tout simplement $(window).scrollTop(1000) - d'après mon expérience, cela ne fonctionne pas dans environ 50 % des cas).

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X