Vous êtes ici : Accueil du blogjQuery » Un défilement animé (« Smooth scroll ») en jQuery sans plugin

Un défilement animé (« Smooth scroll ») en jQuery sans plugin

Nous avons vu précédemment comment réaliser un site de type one page en full CSS. On va maintenant égayer la navigation entre les rubriques en y ajoutant un effet de défilement animé (« smooth scroll ») en jQuery.

Cet effet sera déclenché au clic sur un élément ayant une classe js-scrollTo (cela permet de ne pas limiter son application au menu et de faire fonctionner le défilement également sur des liens internes). Le préfixe js- permet de différencier les classes à vocations cosmétiques de celles dédiées à l’interactivité JS.

Voir la démo

Exemple avec les liens du menu :

<ul class="menu">
	<li><a class="js-scrollTo" href="#page-1">Page1</a></li>
	<li><a class="js-scrollTo" href="#page-2">Page 2</a></li>
</ul>

<div id="page-1">
	<!-- Contenu Page 1 -->
</div><!-- /page-1 -->

<div id="page-2">
	<!-- Contenu Page 2 -->
</div><!-- /page-2 -->

Le code javascript (à placer dans <head> ou juste avant </body>) permettant de réaliser le défilement :

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
	$(document).ready(function() {
		$('.js-scrollTo').on('click', function() { // Au clic sur un élément
			var page = $(this).attr('href'); // Page cible
			var speed = 750; // Durée de l'animation (en ms)
			$('html, body').animate( { scrollTop: $(page).offset().top }, speed ); // Go
			return false;
		});
	});
</script>

La méthode .offset() renvoie les coordonnées (relatives au document) de l’élément (ici la page ciblée). On modifie la position de la scrollbar (grâce à scrollTop) jusqu’à atteindre cet élément, en animant le défilement avec .animate().

Commentaires (48)

Lâcher un com'

  1. marco/graphik
    18 mars 2014 à 10h01

    Merci pour ce tutoriel clair et concis, je pensais que c’était beaucoup plus complexe à réaliser. Ça a marché du premier coup, je suis super content !

  2. Fab
    22 avril 2014 à 20h37

    Très simple, merci !

  3. Christophe
    01 mai 2014 à 10h31

    Super simple et facile à intégrer, Merci !

  4. Yo
    06 juin 2014 à 16h47

    Efficace, merci !

  5. Alice
    18 juin 2014 à 17h07

    Super simple, merci beaucoup !!

  6. minimoi
    11 juillet 2014 à 20h00

    bonsoir, une petite question, lorsque j’utilise le plugin, qui fonctionne très bien, mon slider (qui utilise lui aussi du Jquery) ne fonctionne plus, idée?

  7. BeliG
    12 juillet 2014 à 09h38

    @minimoi :
    Bonjour, pas de raison que ce bout de code empêche votre slider de fonctionner, sauf si :

    Vous appelez 2 versions différentes de jQuery qui entrent en conflit
    => Vérifiez les appels de la librairie dans votre source

    Votre slider utilise également une classe « scrollTo »
    => Changez le nom de la classe utilisé pour le smooth scroll

    Mais sans voir la page qui pose problème, difficile d’en dire plus…

  8. Max
    20 juillet 2014 à 00h48

    Bonsoir,
    Y aurait-il une solution pour faire fonctionner le script pour un défilement à l’horizontal ?

  9. BeliG
    20 juillet 2014 à 10h48

    @Max :
    Bonjour,
    En utilisant les méthodes jQuery relatives à la position et aux coordonnées horizontales (plutôt que verticales), cela devrait fonctionner.

    Donc, à la place de :
    scrollTop: $(page).offset().top

    Essayer :
    scrollLeft: $(page).offset().left

  10. Max
    20 juillet 2014 à 14h51

    Merci beaucoup ! Ça fonctionne parfaitement.

  11. Thibaut
    25 septembre 2014 à 14h17

    Vraiment simple d’utilisation, merci pour ce tuto !

  12. BaronneSteel
    03 octobre 2014 à 06h41

    Salut! simpléfficace … merci beaucoup :-)

  13. Sylvain
    15 octobre 2014 à 10h21

    merci ;) simple et efficace !

  14. Myhia
    11 novembre 2014 à 15h48

    Bonjour,

    J’essaye ce code là pour ma web app sur ipad mais…ça marche pas :(

  15. Simon
    15 novembre 2014 à 10h14

    Bonjour bonjour !

    Tout d’abord merci pour ce morceau de code qui marche du premier coup !

    Mais il ne marche pas sur IE, une idée d’un bout de code pour le fix ?

  16. BeliG
    15 novembre 2014 à 12h03

    Bonjour,

    @Myhia :
    Pas de raison que le script ne fonctionne pas sur ta web app, le problème vient donc d’autre chose.

    @Simon :
    Le script devrait fonctionner sans souci sur IE, la preuve avec la démo. Le problème est ailleurs !

  17. Alex
    19 décembre 2014 à 19h13

    Super script merci, est-ce qu’il y a moyen de laisser un offset une fois arrivé à destination? J’ai une barre de navigation fixe et quand ça scroll mon titre arrive derrière ma barre.

    Merci :D

  18. BeliG
    20 décembre 2014 à 11h09

    @Alex :
    Hello, il est préférable d’effectuer ce type d’ajustement en CSS plutôt qu’en JS. Tu peux par exemple ajouter du « padding-top » à ton titre, pour dégager un peu d’espace et éviter le chevauchement des deux éléments.

  19. sandy
    01 février 2015 à 17h24

    Simple et efficace ! ;-)
    Merci beaucoup !

  20. Antoine
    27 février 2015 à 11h59

    Code optimisé :) :

    $('.scrollTo').click( function(event) {
       event.preventDefault();
       event.stopPropagation();
       var url = $(this).attr('href');
       var hash = url.substring(url.indexOf('#'));
       $('html, body').animate( { scrollTop:    $(hash).offset().top }, 750 );
    });

  21. BeliG
    01 mars 2015 à 09h27

    Bonjour Antoine et merci pour ta participation. :)

    event.preventDefault();
    event.stopPropagation();

    Je pense que cela revient plus au moins au même que d’utiliser return false (check this). A la limite si l’on souhaite arrêter l’animation avant d’en lancer une autre je pencherais plutôt pour stop().animate().

    var hash = url.substring(url.indexOf('#'));
    Dans ton exemple (et avec mon DOM), hash contient la même chose que url, alors je n’ai pas compris. :)

  22. Tidjy
    29 mars 2015 à 21h11

    Pour affiner l’effet de passage d’une ancre à une autre en donnant un effet de scroll plus fluide ou plus personnalisé :

    var speed = 750;
    var easing = 'easeInQuad'; // https://jqueryui.com/easing
    $('html, body').animate( { scrollTop: $(page).offset().top }, speed, easing );

    N’oubliez pas d’appeler jQuery UI évidemment pour que cela fonctionne correctement.

  23. Fotsing
    07 avril 2015 à 10h29

    thanks :D

  24. nakarat-i
    09 avril 2015 à 09h29

    Merci c’est génial de trouver un tuto aussi efficace !

  25. AntoineP
    24 avril 2015 à 09h15

    Bonjour et merci beaucoup :) Extrêmement simple d’utilisation !

    Malheureusement j’ai le même soucis que « monimoi » en début de commentaires.

    > Dès que j’insère le script, mon menu responsive ne s’affiche plus, et mon bouton pour remonter au dessus de la page quand on est en bas non plus. Quand j’enlève le script, cela refonctionne.

    Comme vous l’avez conseillé, j’ai changé le nom de la classe « ScrollTo » mais ce n’est pas ça. Je ne vois donc que la version jQuery qui ne doit pas être la bonne.

    Existe t-il un moyen simple de savoir quelle version mettre, ou bien comment trouver la version utilisée de base sur mon site (thème wordpress) ?

    merci beaucoup :)

  26. BeliG
    24 avril 2015 à 20h03

    Bonjour Antoine,

    Il ne s’agit pas de mettre une autre version de jQuery, mais simplement de ne pas en charger 2 différentes.

    Tu peux garder celle utilisée par ton thème wordpress, il suffit juste de ne pas appeler celle indiquée dans le script. La ligne suivante est donc à supprimer :

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

  27. Vincent79
    27 juin 2015 à 10h22

    Merci pour ce script ! Y’a t’il moyen de modifier l’offset ? J’aimerais ajouter une marge à l’ancre (j’ai un menu fixe en haut de ma page et une partie des divs appelées est cachée)
    Qqchose comme { scrollTop: jQuery(page).offset().top -50 } ?

  28. BeliG
    28 juin 2015 à 08h32

    Bonjour Vincent,

    Oui pas de souci cela doit fonctionner comme tu l’as écrit.

    Une autre solution pour éviter de manipuler dans le JS des données spécifiques à ton design serait d’utiliser des éléments cachés dédiés à l’ancrage :

    <div class="page">
       <div id="page-1" class="page-ancre"></div>
       <!-- Contenu Page 1 -->
    </div>

    .page { position:relative; }
    .page-ancre { position:absolute; top:-50px; left:0; }

  29. Sébastien
    25 août 2015 à 14h16

    Salutations et merci pour le code. Fonctionnel et concis !
    Encore merci :)

  30. Marti
    23 septembre 2015 à 09h57

    Bonjour,
    Merci pour ce tuto, très clair.
    Par contre, lorsque je suis sur ma page contact.php et que je veux revenir sur une ancre de la page index.html. Il ne prend pas en compte l’offset. Il y aurait-il une solution ?

    Cordialement, Marti

  31. BeliG
    23 septembre 2015 à 11h28

    Bonjour Marti,

    Difficile de proposer une solution sans voir le problème. Toutefois :
    - Les ancres n’ont rien à voir avec le JS, ça devrait marcher même sans le script. Donc es-tu sûr que le lien de la page contact vers l’ancre de la page index est bon ?
    - Ce n’est pas le même problème qu’ici par hasard ?

  32. Marti
    23 septembre 2015 à 13h41

    @BeliG Merci, oui tu as raison ça ressemble à ce souci. Je vais regarder ça en utilisant des éléments cachés pour l’ancrage.
    La prochaine fois, je lirais avant de poser une question ! ;)
    Encore merci et je crois que je viendrai plus souvent sur ton site car tes tutos sont clairs !

  33. Jonathan
    13 octobre 2015 à 17h12

    Merci INFINIMENT !!!!! Je cherchais laborieusement un moyen simple de produire cet effet sans passer par des codes jquery monstrueux a implémenter et surtout à adapter car je ne suis pas un pro de ce language :) Avec vos explication j’ai tout capté :D !!!! Merci donc encore et bonne continuation.

  34. Richard
    03 décembre 2015 à 15h13

    Simple, efficace, léger… Bref tout ce que j’aime !

    Merci pour cette astuce.

  35. Julien
    30 décembre 2015 à 20h04

    Hey super,

    10mn même pas pour un super résultat, le plus long étant sans doute à définir la bonne vitesse de défilement :)

    Intégration du 1er coup, ta page est de loin la plus claire que j’ai trouvée avec un script qui s’adapte rapidement

    Un grand MERCI, et bonne année ;)

  36. Emilie
    16 janvier 2016 à 17h08

    Super enfin un tuto ultra simple et efficace !
    C’est exactement ce que je cherchais depuis quelque temps mais chaque fois c’était soit en anglais, soit trop lourd et complexe à mettre en place.

    Un grand merci et toute ma reconnaissance éternelle :)

  37. baybay
    21 janvier 2016 à 09h19

    Merci beaucoup !
    Simple et efficace !

  38. dave
    03 février 2016 à 19h44

    Super tuto, simple et efficace ! Merci !
    Je me posais juste une question : peut-on se passer des « par un simple scroll ». Je m’explique : je passe de la page une à la page deux uniquement en scrollant légèrement vers le bas; puis de la page 2 à la page une uniquement en scrollant légèrement vers le haut ?
    Encore MERCI,
    D.

  39. BeliG
    04 février 2016 à 08h48

    Salut Dave,
    Pour réaliser ton effet, l’idée serait de détecter la direction du scroll et d’adapter le script de cet article pour faire défiler vers la page +1 ou -1 (par exemple en manipulant une variable basée sur la page courante).
    Bon courage. :)

  40. dave
    10 février 2016 à 20h54

    Merci pour ta réponse BeliG !
    Bonne continuation et MERCI de nouveau !
    D.

  41. Rillot Gaëtan
    24 mai 2016 à 14h28

    C’est parfait, merci beaucoup pour le script !

  42. Alex
    14 juin 2016 à 15h23

    Super code ! Très simple à utiliser, c’est exactement ce que je cherchais. Merci !!

  43. Nicolas Peters
    01 août 2016 à 20h32

    Rien de plus simple !
    Merci beaucoup !

  44. Bat
    30 août 2016 à 16h14

    Salut,
    le code fonctionne super bien, par contre l’ancre dans mon url ne s’affiche pas et ma div de destination et en display:none à la base et s’affiche avec un :target

    Comment je peux faire pour que l’ancre quand je clique sur mon lien s’affiche dans l’url ?

    Merci d’avance.

  45. BeliG
    31 août 2016 à 08h24

    Hello,

    Il y a des solutions en JS / HTML5 pour mettre à jour l’URL sans recharger la page (#1 / #2), mais ça me semble lourd (et pas adapté) à ce que tu cherches à faire.

    Le plus simple est de revoir la méthode d’affichage de tes sections. Tu as l’id dans la variable page, pourquoi ne pas tout simplement $(page).show() ?

  46. Eyecom
    17 septembre 2016 à 16h49

    merci pour ce petit script

  47. Adrien
    23 octobre 2016 à 15h55

    Grand merci ! c’est très simple et efficace

  48. Yves
    25 novembre 2016 à 11h08

    Merci beaucoup, j’aime les choses simples avec js ;)

Laisser un commentaire

Balises HTML autorisées dans la rédaction du message :
<strong> <a> <code> <q>

Les champs marqués d'une étoile sont obligatoires.

Current month ye@r day *