Ancres et déplacement progressif de l’ascenseur

Une fois n’est pas coutume, voici un petit script jQuery.

NB : Stéphane soulève un problème d’accessibilité dans les commentaires, ne passez pas outre.

Il permet lors de l’activation d’une ancre de déplacer progressivement l’ascenseur de la page en fonction. J’aime personnellement beaucoup cet effet car je trouve qu’il rend plus compréhensible l’utilisation des ancres.

var scrolling = function(){
    var speed     = 1000;
    jQuery('a[href^="#"]').bind('click',function(){
        var id = jQuery(this).attr('href');
        if(id == '#')
            goTo('body');
        else
            goTo(id);
        return(false);
    });
    function goTo(ancre){jQuery('html,body').animate({scrollTop:jQuery(ancre).offset().top},speed,'swing',function(){
            if(ancre != 'body')
                window.location.hash = ancre;
            else
                window.location.hash = '#';
            jQuery(ancre).attr('tabindex','-1');
            jQuery(ancre).focus();
            jQuery(ancre).removeAttr('tabindex');
        });
    }
};

Point par point, cela donne :

var scrolling = function(){

Déclaration de la fonction, qui sera à déclencher au chargement de la page.

    var speed     = 1000;

On choisi une vitesse pour l’effet. Ce paramètre peut être modifié à loisir.

    jQuery('a[href^="#"]').bind('click',function(){

On intercepte le click sur les liens qui renvoient vers des ancres…

        var id = jQuery(this).attr('href');
        if(id == '#')
            goTo('body');
        else
            goTo(id);
        return(false);

Et on déclenche la fonction d’animation en fonction de la destination (haut de page ou ancre). On annule ensuite le comportement par défaut du lien.

    function goTo(ancre){jQuery('html,body').animate({scrollTop:jQuery(ancre).offset().top},speed,'swing',function(){

L’astuce repose sur l’utilisation de la fonction animate, qui pour le coup simplifie bien le code.

            if(ancre != 'body')
                window.location.hash = ancre;
            else
                window.location.hash = '#';

En callback, on prend soin de changer le hash dans la barre d’adresse pour ne pas différer du comportement normal.

            jQuery(ancre).attr('tabindex','-1');
            jQuery(ancre).focus();
            jQuery(ancre).removeAttr('tabindex');
        });
    }
};

On place enfin un tabindex négatif sur l’ancre, afin de pouvoir ensuite forcer le focus dessus. Ainsi, logiquement, même les lecteurs d’écrans devraient s’y retrouver.

On termine enfin par un peu de ménage.

N’hésitez pas à critiquer le tout ! La démo est disponible ici.


39 commentaires ↓

#1 Pascal le 10.05.09 à 12:31

Je trouve l’idée intéressante, tu as un exemple visible ?

#2 Goulven le 10.05.09 à 12:55

On peut voir une tite démo ?

Je suis curieux notamment de savoir si ça n’empêche pas le navigateur d’enregistrer le clic et de permettre de revenir en arrière dans la page (comme je l’avais vu sur certains sites).

(Au passage, il manque un background-repeat:no-repeat; sur la liste MarkItUp).

#3 tetue le 10.05.09 à 13:57

Si je ne me trompe pas, c’est le principe d’un de mes plugins SPIP préférés, « Ancres douces » que l’on peut apprécier sur les blogs du Monde diplo : afficher un billet commenté, puis sur les ancres de la page qui permettent de sauter aux commentaires, puis d’un commentaire à l’autre, etc.

Comme toi, j’aime beaucoup cet effet, parce qu’il explicite les liens dans la page.

#4 Shemu le 10.05.09 à 17:12

Il me semble qu’il existe un petit plugin « ScrollTo » qui ajoute cet effet de défilement doux en faisant un add-on de la fonction javascript de base « window.scrollTo ».

#5 Vincent le 10.05.09 à 18:34

Voici l’exemple qui va bien rapidement codé.

  • Goulven : OVH a eu quelques soucis cette après-midi, c’est sans doute ça.

  • tetue : du coup, tu charges quelques kilos supplémentaires avec les plugins jQuery d’Ariel Flesler, non ? Ils permettent bien plus de choses mais pour le coup, je n’en avais pas besoin.

  • Shemu : c’est justement le plugin cité plus haut il me semble.

#6 Stéphane Deschamps le 10.06.09 à 17:20

Bien.

Je sape le moral de tout le monde ?

Comme je le disais sur spip-contrib :

Le plugin « ancres douces » me pose des soucis.

Quand on clique sur un lien vers une note de bas de page sur un site normal et qu’on retourne en arrière dans son navigateur avec le clavier (alt+gauche ou retour arrière sous Windows, je n’ai pas de mac sous la main mais je crois me rappeler qu’on a le même type de combinaison), on remonte dans la page à l’endroit qu’on vient de quitter. Tout ça obéit à la mécanique classique du navigateur : le #ancre est considéré comme l’emplacement suivant de l’historique.

Avec « ancres douces », on dirait qu’il part du principe que je n’ai pas quitté l’endroit que je suis en train de lire (un return false en JS). Donc un back me fait partir… à la page précédente. (même s’il remplace à partir du # dans l’URL, en réalité je suppose que c’est juste une astuce dans l’objet URL courant, mais ça ne « déplace » pas réellement le navigateur d’un coup vers l’avant dans son historique —cette dernière remarque est une educated guess, comme on dit quand on veut frimer).

Arglü.

Ce n’est pas stratégique mais pour les niais comme moi qui font tout au clavier, c’est très déstabilisant/inconfortable.

Et c’est le même problème ici… désolé, hein. Je n’ai pas de solution, mais il m’est impossible d’entériner ce genre de système tant que je n’aurai pas de solution à prposer.

#7 Vincent le 10.06.09 à 18:47

Je ne comprend pas Stef, j’ai justement un comportement normal au niveau de l’historique moi.

Tu as testé avec un navigateur particulier ?

Je viens de le faire avec Firefox, Safari et Opera sous mac. Idem sous Firefox et IE PC.

#8 Anonyme le 10.12.09 à 13:43

Tu ne voudrais pas reproduire ton article sur jquery.info ?

#9 Stéphane Deschamps le 10.13.09 à 15:36

@Vincent : tu as un Mac ou un Windows sous la main ?

Firefox/Win : je clique sur « bas », ça scrolle gentiment.

Je fais back et je reste comme un gros niais en bas de page… et je suis triste… 😉

#10 Vincent le 10.13.09 à 15:42

Ok Stéphane, compris !

Le souci devrait pouvoir se corriger facilement en ajoutant une « ancre vide » au chargement de la page non ?

Je vais essayer ça.

#11 Vincent le 10.13.09 à 15:56

Bon… ça ne marche pas. Je suis triste aussi tiens.

:(

#12 Stéphane Deschamps le 10.13.09 à 19:58

Voilà. Tu vois mieux mon problème, maintenant ? Pour l’instant, pour moi, c’est insoluble.

#13 Vincent le 10.13.09 à 20:17

C’est problématique oui.

Néanmoins le confort apporté (notamment pour les utilisateurs néophytes) est certain. Et le cas d’utilisation que tu pointes du doigt est relativement peu fréquent.

J’avoue que je suis mitigé…

Tu conseilles de mettre à la poubelle dans tous les cas toi ?

#14 Bruno le 10.15.09 à 7:57

Je cherchais justement un effet similaire sur des pages faisant déjà appel à la bibliothèque jquery. ce script est vraiment très bien 😉 Pour contourner le problème évoqué par Stéphane (ne pas casser l’historique de navigation), il suffit de remplacer return (false) par void(0)

#15 Vincent le 10.15.09 à 9:44

On dirait bien que ça marche : merci Bruno !

#16 Stéphane Deschamps le 10.27.09 à 18:30

Bravo Bruno ! Génial !

(je vais vite le redire sur spip-contrib) :)

#17 Zacos le 03.29.10 à 11:08

Bonjour, etd’abord bravo, cet effet est exactement ce que je cherchais. A un bémol près, que je vous soumets  : avant que le script ne fasse « glisser » la page, l’ancre html a le temps de fonctionner. Du coup, avant l’effet de glissement, on a le temps de voir l’endroit cible pendant une fraction de seconde. Pour détailler ce qui se passe, au moment du clic, la page saute instantanément à la position de l’ancre, puis revient instantanément au point de départ pour retourner (en glissant harmonieusement, cette fois) vers la position de l’ancre. Lorsque la page ne contient que du texte, l’oeil ne s’en rend pas compte, mais lorsqu’il y a des images en décor de page, c’est flagrant, on a le sentiment d’un bug. Les programmeurs émérites que vous êtes auraient-ils une solution (je ne suis qu’un modeste graphiste ignorant de javascript, avec seulement quelques bases en AS3) ?

#18 Thibaut le 07.28.10 à 14:39

Bonjour,

Je me pose exactement la même question! Ce code fonctionne à merveille mais cet effet subliminal est dérangeant. Si une solution existe elle serait la bienvenue !

#19 Ekho le 09.20.10 à 19:51

Merci ! Exactement ce que je cherchais. J’ignore pourquoi, le bout de code précédent que j’utilisais pour faire la même chose sur mon blog a cessé de fonctionner…

Merci encore.

#20 Caga le 10.07.10 à 10:23

Serait il possible d’éviter d’avoir une mise en valeur (rectangle bleu sur chrome, rectangle en pointillé sur firefox) de l’ancre visée ?? c’est assez génant, et je ne vois pas d’ou cela vient. Merci

#21 Vincent le 10.07.10 à 10:29

C’est un point important qui permet de rendre la technique accessible, ce qui était mon postulat de départ.

#22 Caga le 10.07.10 à 10:37

(La réponse m’est destinée ??)

#23 Vincent le 10.07.10 à 10:53

Oui, oui. :)

#24 Caga le 10.07.10 à 10:55

Je n’ai pas compris alors … tu veux dire que l’effet que j’aimerais éviter est justement voulu ? (Si oui, comment je fais pour l’enlever ?)

#25 Vincent le 10.07.10 à 11:00

Moi, je le veux… donc je ne l’enlève pas. 😉

Et c’est pour le coup une bonne pratique donc je te conseille de faire de même. Mais tu peux chercher du côté de CSS sinon, avec focus…

#26 Caga le 10.07.10 à 11:08

?? une bonne pratique, peut être, mais ce rectangle bleu est moche … enfin merci.

#27 P2D le 01.12.11 à 13:33

Terrible merci… 😉

#28 Hicham le 03.03.11 à 12:02

Bonjour,

merci pour le tuyau !

Je suis en pleine refonte de site passant du flash au css, et ce tuto m’est d’une trés grande utilité.

Muchas gracias !

#29 Franks le 03.06.11 à 17:22

Pour le cadre pointillé, enlève : jQuery(ancre).focus();

#30 Didier le 04.24.11 à 14:04

Une petite question de débutant …

Cette fonction qui est plus qu’intéressante mais cependant ne fonctionne que pour les liens qui ressemblent à :

<a href="#ancre"></a>

mais comment faire pour les liens qui ressemblent à:

<a href="ma_page.php#ancre"></a> ?

J’ai essayé et ça ne fonctionne pas. Alors je me suis dis que ca proviendrai surement de cette ligne :

jQuery('a[href^="#"]').bind('click',function(){

Mais je ne parviens pas à la modifier, je suis un peu nul en expressions régulières.

Pouvez vous éclairer ma lanterne ?

Merci !

#31 Anonyme le 05.11.11 à 16:15

Pour Zavo, c’est le remplacement du return (false) par void(0) qui pose ce problème. ++ O

#32 geekman01 le 05.10.12 à 8:01

Bonjour ce script m’arrange bien mais me pose un probleme qui est que je suis oblige de cliquer deux fois sur le lien pour obtenir l’effet scroll! Quelqu’un peut m’aider?

#33 Piin-pin le 05.14.12 à 16:19

Une petite question de débutant …

Cette fonction qui est plus qu’intéressante mais cependant ne fonctionne que pour les liens qui ressemblent à :

mais comment faire pour les liens qui ressemblent à:

 ?

J’ai essayé et ça ne fonctionne pas. Alors je me suis dis que ca proviendrai surement de cette ligne :

jQuery(‘a[href^= »# »]’).bind(‘click’,function(){

Mais je ne parviens pas à la modifier, je suis un peu nul en expressions régulières.

Pouvez vous éclairer ma lanterne ?

Merci !

Je reprends la demande de Didier toujours en attente d’une réponse, car je suis moi même confronté à un soucis. Le script intercepte le clic sur le lien. Mais là je souhaiterais lancer l’animation une fois le chargement de la page terminé… donc avec ce type d’url: http://monsite.fr#ancre

Merci

#34 dodo06 le 05.16.12 à 17:37

Bonjour,

J’ai réalisé un « menu fixe » d’une hauteur 80 pixels sur ma page html. J’ai rajouté des liens internes (Ancre1) et des Ancres internes ()sur cette page pour accéder directement à l’information.

Le problème, c’est que le positionnement de la page se fait toujours sous le « menu fixe », je suis ensuite obligé de déplacer l’ascenseur verticalement pour arriver au bon endroit.

Comment rajouter un décalage (Offset) de 80 pixels quand je clique sur les liens internes?

Voici le lien avec mon exemple: http://www.asd-multimedia.com/test/ Merci pour votre aide.

#35 Nicoco le 09.04.12 à 12:27

Merci pour ce Script ainsi qu’à tous ceux qui ont permis à résoudre certains problème…!

#36 Sébastien le 10.30.12 à 12:43

Mercip our ce script, mais même problème que Piin-pin, personne n’a la solution à ce problème? Merci

#37 Un design collaboratif d’interface » Webdesign Friday (#wdfr) le 11.02.12 à 11:14

[…] […]

#38 Philippe le 03.06.13 à 16:25

Je suis très intéressé par cette fonction, mais le cadre bleu hideux qui apparait sur les ancres cibles gâche tout. Franchement, c’est juste pas possible pour 99% des designs web. En plus ça n’apporte rien à part polluer la mise en page. Je suis très embêté car je ne peux pas utiliser ce script si je ne peut pas enlever ce rectangle bleu. Je suis graphiste, pas développeur, et mes notions en code se limitent presque au copier coller.

Comment supprimer ce défaut simplement pour ne conserver que l’effet d’ascenseur progressif ?

Quelqu’un a t-il trouvé un autre tutoriel simple ? Merci.

#39 serge le 03.18.13 à 10:36

bonjour

effet tres interessant… j’essaie de comprendre mais evidemment ça ne marche pas…je voudrais l’appliquer au rafraichissement et positionnement d’une liste apres saisie dans un pop-up externe cest a dire avec generation dynamique de l’ancre sur une ligne precise

je ne comprends pas tout le code mais en fait il faudrait declencher sur l’evenement onload de la page (sans clic) pour que le positionnement soit automatique au re-chargement surement possible mais je ne suis pas expert en jquery

merci d’avance si vous pouvez m’eclairer


Laisser un commentaire

Mise en forme : vous pouvez utiliser la syntaxe Markdown. Vous verrez, c’est chouette !