Jquery – Défilement fluide (scroll) vers une ID, une ancre

Faire un lien vers une ancre n’est pas bien compliqué. Mais si on souhaite l’animer, faire glisser toute la page vers ce lien, cela devient un peu moins simple. C’est ce que nous allons voir ici avec l’utilisation de jquery.

D’abord faisons notre lien vers notre ancre

1
2
3
4
5
<a href="#ancre">Le lien</a>
 
Plus loin dans la page, vous intégrez l'ancre
 
<a id="ancre"></a>

Animons maintenant notre lien

Il nous faut jquery et notre fichier externe de script

1
2
<!-- A placer en fin de document juste avant la balise </body> 
pour que la page charge plus vite --><script type="text/javascript" src="js/jquery.js"></script><script type="text/javascript" src="js/mesfonctions.js"></script>

Dans mesfonctions.js, on écrit le code nécessaire à notre animation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$(document).ready(function(){
    // au clic sur un lien
    $('a').on('click', function(evt){
       // bloquer le comportement par défaut: on ne rechargera pas la page
       evt.preventDefault(); 
       // enregistre la valeur de l'attribut  href dans la variable target
	var target = $(this).attr('href');
       /* le sélecteur $(html, body) permet de corriger un bug sur chrome 
       et safari (webkit) */
	$('html, body')
       // on arrête toutes les animations en cours 
       .stop()
       /* on fait maintenant l'animation vers le haut (scrollTop) vers 
        notre ancre target */
       .animate({scrollTop: $(target).offset().top}, 1000 );
    });
});

Et enfin l’exemple

Voir l’exemple en ligne

Note

Afin que l’évènement ne se produise pas sur tous les liens et que tous les liens de votre page ne deviennent inactifs, vous avez au moins deux solutions

1. Déclencher l’évènement au clic sur un lien ayant la classe ‘scroll’ par exemple
Le lien devient donc :

1
<a href="#ancre" class="scroll">Le lien</a>

Le JS devient

1
2
3
4
5
6
7
$(document).ready(function(){
    // au clic sur un lien
    $('a.scroll').on('click', function(evt){
      // ici on réécrit le js vu auparavant, rien ne change.  
 
    });
});

2. Ou alors ne le déclencher que si un lien avec une ancre est cliquée

Le JS devient

1
2
3
4
$(document).ready(function(){
    // au clic sur un lien avec une ancre, contenant donc un #
    $('a[href^="#"]').click(function(){ le reste du code au début ici });
});

24 réponses sur “Jquery – Défilement fluide (scroll) vers une ID, une ancre”

  1. Bonjour, merci pour ce partage.

    Pour utiliser ce code, j’ai néanmoins du rajouter une classe à la cible de l’événement afin que l’événement ne se produise pas sur tous les liens, provoquant sinon une impossibilité de naviguer vers d’autres pages.

    1. Pas la peine d’ajouter une classe à ta cible,il suffit d’indiquer le type de lien sur lequel tu souhaites cliquer :

      1
      
      $('a[href^="#"]').click(function(){

      ici au clic sur un lien commencant par un # on déclenche notre fonction

  2. Bonjour, merci pour le partage.

    Par contre chez moi l’effet ne s’affiche pas, lorsque je clique sur un lien, il descend toujours d’un coup, sans défiler… J’ai mis le bout de code en bas de page avant le fin de body et créé la page « mesfonctions.js » :/

          1. ;-) , en fait que tu l’ai mis dans le head ce n’est pas grave du moment que ton appel à jQuery se fait avant ton fichier de fonction perso.

            Je mets les fichiers JS dans le footer pour charger plus rapidement la page quand c’est possible.

            1. mais il ne faut pas ajouter autre chose que j’ai oublié ? Parce que ça ne fonctionne pas chez moi et je comprends vraiment pas pourquoi et c’est vraiment un effet très demandé pour les sites en scroll down :)

            2. je viens d’aller voir ton site : tu as fait 2 appels à jquery . Le premier dans le header et le second dans le footer. Garde le premier car de toute manière le deuxième retourne une erreur 404 (tu n’as mis de fichier jquery.js).

              + tu fais appel à un fichier ajs.js qui n’existe pas non plus. Ces appels sont faites avant le fichier mesfonctions.js

              enfin pour tes liens écrit plutôt #accueil au lieu de index.html#accueil , tu n’as pas besoin du index.html devant le #

  3. Hello,

    Tout d’abord, je te remercie beaucoup, c’est magnifique et 1000 fois plus simple que la plupart de ceux que j’ai testé.

    Cela dit, j’aime me simplifier la vie et j’ai décider de mettre des ancres dans une div qui se trouve plus bas dans la page et cette div est scrollable horizontalement.

    Quand je clique sur une ancre, l’animation se fait niquel jusqu’à la div scrollable mais ne se déplace horizontalement jusqu’où je veux.

    Est-ce compréhensible ? C’est dur à expliquer.

    html: ————————————————-

    1
    
        <a href="#three" rel="nofollow">Aller vers l'ancre</a>

    CSS: ————————————————–

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    #home {
    	width:100%;
    	height:55.55%;
    	background-color:#233445;
    }
     
    #container {
        width: 100%;
        background-color: #CCC;
        overflow: auto;
        overflow-y: hidden;
        height: 45.5%;
        white-space:nowrap;
    }
     
    .contents {
        width: 100%;
        height: 100%;
        display:inline-block;
    }
    #one {
        background-color:white;
    }
    #two {
        background-color:#333;
    }
    #three {
        background-color:white;
    }
    #four {
        background-color:#AAA;
    }

    Le but serait donc que l’ancre fonctionne horizontalement.

    Bonne soirée !

    1. Hello Timothy,

      Réponse un peu tardive.

      J’ai bien compris ce que tu voulais faire , enfin je crois.

      En premier lieu faire un défilement vertical vers ton ancre puis un défilement horizontale vers la partie de la div qui t’intéresse.

      Dans ton cas voila comment je procéderais :

      1. Pour le défilement vertical, on fait comme nous l’avons vu dans cette article.
      2. pour le défilement horizontal, je crée un système de slider : où il y a une zone visible contenant une bande qui regroupe tous mes blocs qui ont une taille définie.

      exemple :
      #container: 900px ou 100% : ce que nous voyons réellement
      #container-global : 300px*4 : contient nos 4 blocs
      .contents : 300px; : class ajouter à nos blocs #one, #two etc

      au clic , je défile verticalemrnt puis je défile horizontalement vers le bon slide pour faire cela j’utilise :

      $(‘#container-global’).animate({‘left’: left});

      ou left = la distance qui sépare notre bloc (#one, #two, #trhee ou #four) de l’origine.

      Donc : left sera égale à 0 pour #one, -300 pour #two, -600 pour #three et -900 pour #four

      Sachant que notre défilement dure un certain temps, j’ajouterai un delay avant de faire le défilement horizontal sinon les deux se font en même temps.

      Bon , c’est une explication très (trop ?) rapide , j’essaye d’en faire un article pour mieux l’expliquer

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      
      $(document).ready(function(){
          // au clic sur le lien 4
          $('#four').on('click', function(evt){
             // bloquer le comportement par défaut: on ne rechargera pas la page
             evt.preventDefault(); 
             // enregistre la valeur de l'attribut  href dans la variable target
      	var target = $(this).attr('href');
             /* le sélecteur $(html, body) permet de corriger un bug sur chrome 
             et safari (webkit) */
      	$('html, body')
             // on arrête toutes les animations en cours 
             .stop()
             /* on fait maintenant l'animation vers le haut (scrollTop) vers 
              notre ancre target */
             .animate({scrollTop: $(target).offset().top}, 1000 );
             $('#container-global').delay(1000).animate({‘left’: (-4*300) });
          });
      });

      +++

  4. Bonjour,
    Merci beaucoup pour ces explications. Le rendu est super.. enfin, pas encore chez moi. ;-)
    Est-ce qu’il est possible de l’appliquer sur un site sous WordPress ?
    Et si oui, comment ?
    Merci beaucoup!
    Bonne journée!
    Sacha

  5. Bonjour,

    je travail sous joomla et j’ai essayé d’intégré ce code.
    J’ai du y apporter une modification car il a commencé par tuer tous les liens de la page y compris mon menu j’ai donc retirer la fonction : evt.preventDefault();

    J’ai récupéré l’usage de mes liens mais l’effet n’est toujours pas la :(

  6. Bonjour,
    Je cherche de l’aide parce que j’ai un conflit entre 2 javascript et j’avoue patauger en javascript. Le premier me sert de carrousel et le deuxième (le votre) de scroll pour un défilement fluide avec ancres dans mon site.
    Pour le votre j’ai essayé celui-ci:

    1. Déclencher l’évènement au clic sur un lien ayant la classe ‘scroll’ , donc dans mon site:

    $(document).ready(function(){
    // au clic sur un lien
    $(‘a.scroll’).on(‘click’, function(evt){
    $(document).ready(function(){
    // au clic sur un lien
    $(‘a’).on(‘click’, function(evt){
    // bloquer le comportement par défaut: on ne rechargera pas la page
    evt.preventDefault();
    // enregistre la valeur de l’attribut href dans la variable target
    var target = $(this).attr(‘href’);
    /* le sélecteur $(html, body) permet de corriger un bug sur chrome
    et safari (webkit) */
    $(‘html, body’)
    // on arrête toutes les animations en cours
    .stop()
    /* on fait maintenant l’animation vers le haut (scrollTop) vers
    notre ancre target */
    .animate({scrollTop: $(target).offset().top}, 1000 );
    });
    });

    });
    });

    (seulement que faut-il mettre dans le css pour le scroll ?)

    Ensuite pour mon carrousel, j’avais créé des liens externes vers d’autres sites en cliquant sur les images.

    Seulement voilà:
    cette petite ligne dans votre java :
    $(‘a.scroll’).on(‘click’, function(evt)
    m’empêche par la suite d’avoir mes liens qui se trouvent dans mon carrousel.

    Une idée svp ?

    Je vous joins également le java de mon carrousel (désolée il est très long) :

    $(function() {
    function setupSlide( $slide ) {
    $slide.find(‘.large’).addClass( ‘back’ )
    .find(‘img’).css({
    marginTop: 325,
    marginLeft: 50,
    width: 400
    });
    $slide.find(‘.small’).addClass( ‘back’ )
    .find(‘img’).css({
    marginTop: 325,
    marginRight: 50,
    width: 300
    });
    }
    function slideIn( $slide ) {
    $slide.find(‘.large img’)
    .animate({
    width: 450,
    marginLeft: 0
    }, {
    queue: false,
    duration: _duration * 1.5
    })
    .animate({
    marginTop: -10
    }, {
    duration: _duration,
    complete: function() {
    $slide.find(‘.large’).removeClass( ‘back’ );
    }
    })
    .animate({
    marginTop: 50
    }, {
    duration: _duration / 2
    });

    $slide.find(‘.small img’)
    .delay( _duration )
    .animate({
    marginTop: 50
    }, {
    duration: _duration,
    complete: function() {
    $slide.find(‘.small’).removeClass( ‘back’ );
    }
    })
    .animate({
    marginTop: 100
    }, {
    duration: _duration / 2
    });
    setTimeout(function() {
    $slide.find(‘.small img’)
    .animate({
    width: 350,
    marginRight: 0
    }, {
    queue: false,
    duration: _duration
    });
    }, _duration * 1.5);
    }
    function slideOut( $slide ) {
    $slide.find(‘.small img’)
    .animate({
    width: 300,
    marginRight: 50
    }, {
    queue: false,
    duration: _duration * 1.5
    })
    .animate({
    marginTop: 50
    }, {
    duration: _duration / 2,
    complete: function() {
    $slide.find(‘.small’).addClass( ‘back’ );
    }
    })
    .animate({
    marginTop: 325
    }, {
    duration: _duration
    });
    $slide.find(‘.large img’)
    .delay( _duration / 2 )
    .animate({
    marginTop: -15
    }, {
    duration: _duration / 2,
    complete: function() {
    $slide.find(‘.large’).addClass( ‘back’ );
    }
    })
    .animate({
    marginTop: 325
    }, {
    duration: _duration
    });
    setTimeout(function() {
    $slide.find(‘.large img’)
    .animate({
    width: 400,
    marginLeft: 50
    }, {
    queue: false,
    duration: _duration
    });
    }, _duration / 2);
    }
    var $carousel = $(‘#carousel’);
    var _duration = 500;
    $carousel.carouFredSel({
    items: 1,
    pagination: ‘#pager’,
    scroll: {
    fx: ‘none’,
    timeoutDuration: 4000,
    conditions: function( direction ) {
    if ( $carousel.hasClass( ‘prepared’ ) )
    {
    $carousel.removeClass( ‘prepared’ );
    return true;
    }
    if ( $carousel.hasClass( ‘animating’ ) )
    {
    return false;
    }
    $carousel.addClass( ‘animating’ );
    var $slide = $carousel.children().first();
    slideOut( $slide );
    setTimeout(
    function() {
    $carousel.addClass( ‘prepared’ );
    $carousel.trigger( direction );
    }, _duration * 2
    );
    return false;
    },
    onAfter: function( data ) {
    setupSlide( data.items.visible );
    slideIn( data.items.visible );
    setTimeout(
    function() {
    $carousel.removeClass( ‘animating’ );
    }, _duration * 2.5
    );
    }
    }
    });
    });

    Un très grand MERCI d’avance à celui ou ceux qui voudront bien m’aider.

    1. Chti47,

      Plusieurs remarque par rapport à ton js :

      – $(document).ready(function(){ MES FONCTIONS }); n’est à utiliser qu’une fois ou plûtot ca ne sert à rien de l’imbriquer comme tu l’as fait : On met nos fonctions à l’intérieur pour être sûr que le DOM soit chargé et qu’il soit prêt à être parcouru et manipulé.

      1
      2
      3
      4
      5
      6
      7
      8
      
      - $(‘a.scroll).on(‘click’, function(evt){});
      /* ceci veut dire que l'évènement sera déclenché seulement au clic 
      sur les liens dont la classe est .scroll : */
       <a class="scroll" href="#" rel="nofollow">
       
      - $(‘a’).on(‘click’, function(evt){});
      /* ceci veut dire que l'évènement sera déclenché au clic sur 
      n'importe quel lien*/

      Si tu as bien utilisé – $(‘a.scroll’).on(‘click’, function(evt){}); , ton carousel ne devrait pas être impacté sauf si tu as donné une classe scroll à tes liens dans ton carousel. Si c’est le cas change la classe du a.scroll

  7. Re -bonjour,
    Je viens de voir la solution à mon problème un peu plus haut sur le forum, c’était le evt.preventDefault(); qu’il fallait enlever ;) .Seulement voilà, maintenant le lien n’est plus aussi fluide que ça,il affiche très rapidement la page du lien, puis fait le défilement normalement.C’est pas très beau. Une idée à ma donnée? svp.
    Merci

    1. evt.preventDefault(); permet d’éviter que l’action associée à évènement ne se produise pas.

      Dans notre cas , le clic sur « a » qui devrait normalement nous faire changer de page ne fera rien.

      Il est donc nécéssaire ici.`

      Tu es sur d’avoir lu les explications fournit avec le code, au dessus evt.preventDefault(); de il y avait écrit :

      // bloquer le comportement par défaut: on ne rechargera pas la page

      Car si tu fais juste un copier coller, je comprends que tu galères :(

  8. Bonjour, après avoir suivi en détail ce que vous proposez, il m’est impossible de charger l’animation. Pouvez-vous m’aider ?
    Pour info, mes ancres fonctionnent bien mais sans l’animation, et j’ai rajouter un decalage de 80pixels car j’ai figé mon header.
    Merci d’avance.
    Marvin

    html>

    new-slm-design-sportslocalmedia


    $(document).ready(function(){
    // au clic sur un lien avec une ancre, contenant donc un #
    $(‘a[href^= »# »]’).click(function(){
    // bloquer le comportement par défaut: on ne rechargera pas la page
    evt.preventDefault();
    // enregistre la valeur de l’attribut href dans la variable target
    var target = $(this).attr(‘href’);
    /* le sélecteur $(html, body) permet de corriger un bug sur chrome
    et safari (webkit) */
    $(‘html, body’)
    // on arrête toutes les animations en cours
    .stop()
    /* on fait maintenant l’animation vers le haut (scrollTop) vers
    notre ancre target */
    .animate({scrollTop: $(target).offset().top + 80}, 1000 );
    });
    });

  9. bonjour, j’ai mis le code suivant pour qu’il me détecte les liens qui renvoient sur une ancre. Cela fonctionne sauf au premier clic (où il m’emmène à l’ancre directement sans mouvement). quelqu’un a une idée ? Merci !!

    $(document).ready(function(){
    // au clic sur un lien avec une ancre, contenant donc un #
    $(‘a[href^= »# »]’).click(function()
    {

    // au clic sur un lien
    $(‘a’).on(‘click’, function(evt){
    // bloquer le comportement par défaut: on ne rechargera pas la page
    evt.preventDefault();
    // enregistre la valeur de l’attribut href dans la variable target
    var target = $(this).attr(‘href’);
    /* le sélecteur $(html, body) permet de corriger un bug sur chrome
    et safari (webkit) */
    $(‘html, body’)
    // on arrete toutes les animations en cours
    .stop()
    /* on fait maintenant l’animation vers le haut (scrollTop) vers
    notre ancre target */
    .animate({scrollTop: $(target).offset().top}, 1000 );
    });

    });
    });

  10. Quand j’ajoute le script dans mon code, mes ancres ne fonctionnent plus. J’ai également cette erreur : Uncaught TypeError: Cannot read property ‘top’ of undefined.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *