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">Page 1</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 (72)

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

  49. Justine
    06 décembre 2016 à 10h01

    Bonjour, j’ai un petit soucis.

    Je suis sur un thème wordpress et le défilement ne fonctionne pas. Quand je clic sur mon menu, j’atterris bien sur la section voulu mais pas de fluidité du tout.

    Comment je peux faire ?

    Merci

  50. BeliG
    07 décembre 2016 à 10h02

    Bonjour Justine,

    Si on parle de ton blog, je remarque que jQuery est déjà appelé, tu ne dois donc pas ajouter la ligne :
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

    Je vois aussi que chez toi les déclarations jQuery sont « protégées ». Essaye de remplacer :
    $(document).ready(function() {

    par :
    jQuery(document).ready(function($) {

  51. Goms
    18 février 2017 à 01h24

    Ah heureusement que j’ai rencontré cet article

  52. iManFR
    16 octobre 2017 à 15h18

    NIKEL

  53. B3nj4m1n
    27 octobre 2017 à 22h06

    un GRAND MERCI. Simple et efficace.

  54. Zélie Thibault
    12 décembre 2017 à 09h23

    Très rapide et terriblement efficace, merci !

  55. Phen'X
    15 janvier 2018 à 19h06

    Bonjour j’ai un petit problème :
    le code marche très bien pour aller d’une partie de la page à une autre, mais l’effet ne fonctionne pas quand ma balise « a » mène vers href= »# » :/
    merci pour votre aide ;)

  56. BeliG
    16 janvier 2018 à 21h16

    Bonjour,

    Je ne suis pas sûr de comprendre votre problème. C’est l’effet de défilement qui ne fonctionne pas ?

    Vous ne pouvez pas faire défiler vers « # », il faut forcément indiquer l’id d’un élément dans votre page.

    Si vous souhaitez animer un retour vers le haut de la page il vous faut un <div id="header"> et un <a class="js-scrollTo" href="#header">Top</a>

  57. Arnault
    01 avril 2018 à 14h11

    Bonjour,
    Merci pour ce tuto!
    J’aurais voulu savoir comment faire pour qu’il y ait un décalage entre le haut de la page et l’ancre en elle-même, car dans mon cas, une partie de mon texte se retrouve caché derrière le bandeau de mon menu.
    Merci d’avance.

  58. BeliG
    02 avril 2018 à 07h01

    Bonjour Arnault,

    Il y a 3 solutions simples pour régler ton problème :
    => Aérer chacune de tes pages (éléments avec ancres) avec un padding-top correspondant à la hauteur de ton menu.
    => Ajouter dans le JS une valeur permettant de modifier l’offset.
    => Utiliser un élément dédié à l’ancrage positionné en absolute.

    Pour les deux derniers points tu peux jeter un coup d’oeil à ce commentaire.

  59. cherELF
    25 avril 2018 à 17h33

    Bonjour,

    J’ai le même problème que Phen’X:

    Le passage d’une partie à une autre fonctionne, mais pas l’effet de défilement :/

  60. BeliG
    26 avril 2018 à 07h38

    Bonjour cherELF,

    Si l’effet de défilement ne fonctionne pas, c’est qu’il y a un problème avec le JS. Que dit la console (au chargement de la page et lors du clic sur un lien du menu) ?

  61. AMO
    24 mai 2018 à 11h44

    Très clair, merci

  62. Audrey
    01 juillet 2018 à 18h01

    Bonjour,
    super tuto, merci!
    Y a-t-il un moyen de faire un smooth scroll à l’ouverture d’une autre page à laquelle on accède par un lien?
    Je m’explique j’ai un menu avec plusieurs liens donnant sur d’autres pages. J’aimerai que quand on clique sur un lien, il y ait un smooth scroll amenant directement à la partie en dessous de ce menu qui est sur toutes mes pages en question.

  63. BeliG
    02 juillet 2018 à 06h56

    Bonjour Audrey,

    Faire un smooth scroll à l’ouverture d’une page n’est pas quelque chose que les utilisateurs apprécient en général. Le temps que la page et le script se chargent, ils auront sans doute déjà commencé leur navigation. Leur imposer à ce moment un défilement qu’ils n’ont pas demandé n’est pas naturel (et donc désagréable).

    Il vaut mieux les amener directement au contenu souhaité grâce à un système d’ancrage classique.

  64. Johanne
    27 février 2019 à 08h14

    Bonjour,

    Merci beaucoup pour ce tuto ! Simple à mettre en place et hyper pratique ! Je suis super contente, je pense y avoir gagné quelques heures ;)

  65. ay
    13 mai 2019 à 09h54

    Merci beaucoup pour ce tuto efficace.

  66. vinte
    13 février 2020 à 09h33

    Bonjour, j’ai un problème concernant l’animation

    Je fait une vue en javascript à partir d’un fichier json

    le problème vient du faite que lorsque je génère mon html en js (en string avec un for puis innerHTML pour les ajouté), les liens ne s’anime contrairement au lien déjà dans le html.

    j’ai par exemple un navbar qui possède les lien ProposalOverview (dans le html) qui s’anime, mais celui ayant tout les « Proposal » un à un ne s’affiche pas

    merci d’avance si vous avez une solution

  67. BeliG
    13 février 2020 à 13h14

    Bonjour vinte,

    Le code, tel qu’il est écrit dans cet article, attache l’évènement click aux éléments $('.js-scrollTo') au chargement de la page.

    Comme tes liens sont générés dynamiquement, ils ne sont donc pas présents au moment de l’initialisation.

    Pour y remédier, il suffit d’attacher l’évènement au document plutôt qu’aux éléments. Essaye de remplacer :

    $('.js-scrollTo').on('click', function() {

    Par :

    $(document).on('click', '.js-scrollTo', function() {

  68. Gunter Gillot
    16 mai 2020 à 14h31

    Bonjour
    Magnifique, c’est ce que je cherche depuis des mois mais (j’ai mis le script en place mais je ne sais pas quoi faire ensuite et plus particulièrement (à mon avis) il doit y avoir un tag/code à mettre dans la homepage et dans le script mais quoi et oû ?

    Je dois découper ma homepage en 4 ou 5 parties et le système proposé ici est fantastique. Le problème c’est que les non habitués ne savent pas quoi faire …

  69. BeliG
    16 mai 2020 à 15h45

    Bonjour Gunter,

    Si tu as un WordPress et que tu es novice en développement web, ça va être un peu compliqué malheureusement…

    La partie délicate consiste à ajouter un script jQuery à WordPress. Disons-le clairement, les tutos que l’on trouve en ligne en français sont tout pourris. Un jour, peut-être, j’en rédigerai un. En attendant, si tu es (très) motivé, voici un fil de discussion qui pourrait t’aider (c’est le plus simple que j’ai trouvé après 30min de recherche).

    Ensuite, une fois que tu auras découpé ton contenu en plusieurs parties et que tu auras « englobé » chaque partie dans une div avec un id spécifique :

    <div id="home-1">Partie 1</div>
    <div id="home-2">Partie 2</div>
    etc.

    Il faudra ajouter la classe CSS class="js-scrollTo" à chaque lien a de ton menu en précisant la cible href="#home-N".

    Si ton sous-menu est dans le corps de la page (dans wp-content/themes/TONTHEME/index.php ou dans une page WP), ça devrait aller.
    S’il est généré automatiquement via un plugin ou autre, c’est la m*rde.

  70. Gunter Gillot
    16 mai 2020 à 18h05

    Bonjour
    J’ai installé le script, pas de problème à ce niveau. Tu me dis d’inclure les blocs de la homepage dans des DIV – pas de problème mais … TD Composer (Tagdiv) me donne la homepage sans le header et footer cela devrait être simple dans le composeur. Toutefois voici à quoi ressemble la HP en code …

    [tdc_zone type="tdc_content"][vc_row]
    [vc_column width="1/1"][vc_empty_space]
    [td_block_big_grid_1 sort="random_posts" category_id=""]
    [/vc_column][/vc_row][vc_row][vc_column width="1/2"]
    [...]

  71. BeliG
    16 mai 2020 à 20h56

    Je ne connais pas tagDiv.
    Et leur documentation est inaccessible sans compte. 👍

    Le code que tu montres correspond à ce qui est généré à partir des réglages du thème, et ce n’est clairement pas fait pour être modifié comme de l’HTML/CSS classique.
    Comme ils ont mis en place un code propriétaire, tu ferais mieux de te rapprocher de leur support pour obtenir de l’aide.

  72. Jonathan
    03 octobre 2020 à 17h00

    Vos contributions sont très constructif

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 *