La navigation interne dans une page web
La navigation interne à une page web d'un site consiste à utiliser une ancre et y faire référence pour forcer l'affichage du navigateur sur la zone en question. Penchons nous d'abord sur l'utilisation « légacy* » de ce mécanisme et ensuite sur les améliorations ergonomiques envisageables avec du JavaScript (et du jQuery).
* tel qu'il fonctionne de manière standard depuis sa création.
L'ancre interprétée nativement par le navigateur
L'utilisation standard de la balise <a> est celle de permettre la navigation entre différentes pages d'un même site ou d'autre sites/ressources sur la toile.
Une seconde utilisation —celle qui nous intéresse dans cet article— est de permettre la navigation interne à une page. Cette seconde utilisation peu grosso-modo être divisée en 3 types de lien :
- accès rapide : on va plus loin dans la page ("Aller au menu", "Aller à l'article"...),
- navigation interne : réservée pour des intéractions ("Retour en haut de page", "Référence au commentaire 14"...),
- évitement : plus de détails dans l'article Les liens d'évitement - Alsacreations.
Bien que la finalité de chaque utilisation soit différente, le mécanisme de mise en place est identique.
La balise a et l'attribut name
Dans les débuts, il n'y avait qu'une façon d'atteindre une zone précise d'un document : le couple balise <a> et attribut name. Prenons l'exemple d'une phrase présente plus haut dans cet article et voyons comment l'ancrer de manière à y accéder par un lien.
Pour atteindre l'ancre « adefinition » :
<a name="adefinition">*</a> tel qu'il fonctionne de manière standard depuis sa création.
On utilise le lien :
Cliquer sur <a href="la-navigation-interne-dans-une-page-web/#adefinition">Atteindre</a>
Résultat : Cliquer sur Atteindre
Gardez à l'esprit qu'en xHTML ou en HTML5 l'attribut name sur la balise <a> est obsolète.
Note : comme vous pouvez le constater dans notre exemple, la phrase est cachée par le menu. Malheureusement l'ancre ne permet pas de définir une valeur de décalage (offset). On peut facilement envisager d'ancrer un élément plus haut que la zone véritablement souhaitée pour la rendre bien lisible mais QUID de l'accessibilité et de la maintenance des ancres à posteriori.
L'attribut id comme ancre
Puis très vite les navigateurs se sont nativement affranchis de la balise <a name=""> en permettant de cibler n'importe quel élément HTML. Pour cela —parce que l'attribut name n'est pas disponible sur toutes les balises— on utilise l'attribut id disponible sur toutes les balises.
Pour atteindre l'ancre « pdefinition » :
<p id="pdefinition" class="eye-catching"> <a name="adefinition">*</a> tel qu'il fonctionne de manière standard depuis sa création. </p>
On utilise le lien :
Cliquer sur <a href="la-navigation-interne-dans-une-page-web/#pdefinition">Atteindre</a>
Résultat : Cliquer sur Atteindre
Note : vous remarquerez que le système natif impose d'ajouter l'ancre à l'url. Cela peut s'avérer être un avantage pour communiquer l'adresse et la position précise d'un commentaire en un seul lien cependant pour les mécanismes AJAX utilisant le détournement de l'ancre (la partie hash de l'adresse se situant après le « # ») cela est un handicape certain.
Les ancres HTML et le JavaScript
A présent voyons quelques exemples de manipulation d'ancres avec du JavaScript.
Décaller l'affichage de l'ancre du haut du navigateur
Comme noté précédemment, il serait possible de simplement placer son ancre plus haut que l'endroit réel où l'on souhaite arriver. Cependant pour des questions d'accessibilité, il vaut mieux que l'élément ancré soit réellement l'élément que l'on souhaite afficher.
Le script JavaScript ci-dessous va vous permettre de décaler l'affichage de vos ancres :
// Pour tous les liens commençant par #. $("a[href^='#']").click(function (e) { // On annule le comportement initial au cas ou la base soit différente de la page courante. e.preventDefault(); // On ajoute le hash dans l'url. window.location.hash = $(this).attr("href"); // Une fois en place on va forcer l'affichage 40 pixels plus haut. $(window).scrollTop( $(window).scrollTop() - 40 ); });
Exemple : Atteindre #pdefinition avec un offset de -40
Faire défiler la page jusqu'à une ancre
Nous allons rajouter un effet pour surcharger le comportement de base. La page ne sautera plus du lien vers l'ancre, mais accompagnera l'utilisateur jusqu'à l'ancre ce qui lui permettra de ne pas être perdu. Il pourra ainsi appréhender où se situe la nouvelle zone dans la page courante.
// Pour tous les liens commençant par #. $("a[href^='#']").click(function (e) { var yPos, yInitPos, target = ($($(this).attr("href") + ":first")); // On annule le comportement initial au cas ou la base soit différente de la page courante. e.preventDefault(); yInitPos = $(window).scrollTop(); // On ajoute le hash dans l'url. window.location.hash = $(this).attr("href"); // Comme il est possible que l'ajout du hash perturbe le défilement, on va forcer le scrollTop à son endroit inital. $(window).scrollTop(yInitPos); // On cible manuellement l'ancre pour en extraire sa position. // Si c'est un ID on l'obtient. target = ($($(this).attr("href") + ":first")); // Sinon on cherche l'ancre dans le name d'un a. if (target.length == 0) { target = ($("a[name=" + $(this).attr("href").replace(/#/gi,"") + "]:first")) } // Si on a trouvé un name ou un id, on défile. if (target.length == 1) { yPos = target.offset().top; // Position de l'ancre. // On anime le défilement jusqu'à l'ancre. $('html,body').animate({ scrollTop: yPos - 40 }, 1000); // On décale de 40 pixels l'affichage pour ne pas coller le bord haut de l'affichage du navigateur et on défile en 1 seconde jusqu'à l'ancre. } });
Exemple :
- Sur id : Défiler juqu'à #pdefinition
- Sur name : Défiler juqu'à #adefinition
Variante : ne pas conserver le hash dans l'url
Cela permet aux d'applications web avec de l'AJAX se servant du hash pour la navigation globale de ne pas perturber l'adresse. Il suffit de supprimer les lignes suivantes de l'exemple précédent :
... yInitPos, ... yInitPos = $(window).scrollTop(); window.location.hash = $(this).attr("href"); $(window).scrollTop(yInitPos);
Variante : ne pas conserver le hash dans l'url sans défilement
Au cas où vous préféreriez simplement annuler l'ajout du hash, mais conserver le comportement initial (sans défilement) il suffit de remplacer la ligne :
$('html,body').animate({ scrollTop: yPos - 40 }, 1000);
par la ligne
$(window).scrollTop(yPos - 40);
Quoi de plus simple :)
Problème d'ancre avec la balise base
Si vous ne la connaissez pas encore, sachez que la balise <base> permet de choisir la référence d'une url dans le cas d'un appel relatif à une page dans un lien. Elle est réellement pratique pour les fichiers appelés par réécriture d'url incluant donc de faux sous répertoires.
Résoudre un problème...
Voyez plutôt l'exemple :
Je décide de ne pas utiliser d'url absolue car mon site peut changer d'adresse racine. Je n'ai pas envie de changer tous mes liens en base de données si changement d'adresse par exemple. J'utilise donc l'url relative.
À cette adresse http://blog.haeresis.fr/, je dois inclure ma CSS comme suit :
<link type="text/css" rel="stylesheet" href="css/common.css" media="screen" />
Et à cette adresse http://blog.haeresis.fr/categories/, je dois inclure ma CSS comme suit :
<link type="text/css" rel="stylesheet" href="../css/common.css" media="screen" />
Le problème intervient donc dès lors que l'inclusion de <link> est dans un fichier commun à toutes les pages. Avec la réécriture d'url, je n'ai aucune idée du niveau d'arborescence qui sépare mon fichier de la page courante.
Grâce à l'utilisation de <base> avant tous mes liens je peux définir la base de l'appel d'un fichier qui se fait initialement depuis le dossier de l'adresse courante de manière identique à toutes les pages (quel que soit le niveau d'arborescence) et ceux pour tous les liens de la page.
<base href="http://blog.haeresis.fr/" /> <link type="text/css" rel="stylesheet" href="css/common.css" media="screen" />
Cela n'empêchera pas de devoir changer la base s'il y a changement d'adresse du site. Mais le travail est alors minime et les liens relatifs enregistrés en base (ceux d'un article par exemple) marcheront partout, quel que soit la profondeur de l'adresse de l'article.
...peut en apporter un autre
Tout semble aller pour le mieux dans le meilleur des mondes ; mais revenons à notre lien <a href="#pdefinition">. Il pointe maintenant vers la base du site et non plus vers la page courante à cause de <base> ! Cela a pour effet de bord de ne pas atteindre l'ancre dans la page mais de chercher à atteindre l'ancre à l'adresse de <base>. Il faut alors compléter son lien pour se ré-accorder à la base du site.
Nous sommes à l'adresse : http://blog.haeresis.fr/la-navigation-interne-dans-une-page-web/
<head> ... <base href="http://blog.haeresis.fr/" /> ... </head> <body> ... <a href="#pdefinition" title="Atteindre l'ancre">Atteindre l'ancre<a> <a href="la-navigation-interne-dans-une-page-web/#pdefinition" title="Atteindre l'ancre">Atteindre l'ancre<a> ... </body>
Problème : Cette ancre ne marche pas à cause de la base du site
Si vous voulez absolument éviter de réécrire l'url de la page courante (parce que si elle change d'adresse, le monde s'éteindra) vous pouvez remplacer :
<a href="#pdefinition" title="Ancre">Ancre<a>
par :
<a href="#pdefinition" onclick="window.location.hash = 'pdefinition'; return false" title="Ancre">Ancre</a>
ou automatiser le système avec jQuery :
// Pour tous les liens commençant par #. $("a[href^='#']").click(function (e) { e.preventDefault(); // On annule le comportement initial. window.location.hash = $(this).attr("href"); // On change le hash de l'adresse. });
Note : Vous me direz que sans JavaScript on retournera à l'accueil et vous aurez raison...
En conclusion
La simplicité avec laquelle on peut atteindre une ancre s'envole dès l'instant où l'on souhaite faire plus que cela. Ainsi utiliser les ancres avec la balise base, décaler l'offset d'une ancre ou animer la page jusqu'à l'ancre sont autant de tâches réalisables mais qui nécessitent un minimum de connaissances et de précautions.
5 Commentaires
Choisir un Avatar depuis une url
Adresse : (64px x 64px)ou Changer la couleur de fond
et Choisir un Avatar dans la liste
Votre commentaire a été ajouter ci-dessous ! Si vous désirez le supprimer ultérieurement, servez vous du code suivant :
Les commentaires sont actuellement affiché du plus rescent au plus ancien. Vous pouvez inverser l'ordre en cliquant ci-dessous :
Bonjours à tous. Concernant un site d'info pour une Asso, j'ai mis un lien sur l'image d'en-tête pour aller directement en haut de page sans passer par le scroll. Le souci est que ça fonctionne correctement seulement avec Chrome. Sur mozilla et autres le scroll fonctionne mais avec un décalage(c'est trop bas) J'ai regardé l'article "La navigation interne dans une page web" très bien expliqué et qui présente des variantes, mais finalement je me dis que puisque ça fonctionne avec chrome, c'est peut-être une erreur dans le code. Je suis preneur de toute solution, MERCI. http://ucml-49.com/
Je trouve ce commentaire pertinent ?
Merci beaucoup pour ce tuto! vraiment utile!
Petite question, est-il possible de décaler l'affichage des ancres en vh plutôt qu'en px?
Merci!
Je trouve ce commentaire pertinent ?
Un bon article clair et chose rare : un bonne exemple qui marche du premier coup quand on l'utilise dans un site. merci
Je trouve ce commentaire pertinent ?
Dans quel fichier dois-je insérer le bout de code si je suis sur wordpress ?
J'ai essayé de mettre ça dans un fichier js (rangé dans un dossier js) de mon thème, mais ça semble ne pas le prendre en compte. Lorsque j'actualise ma page j'ai l'astuce qui fonctionne sur l'instant, puis, lorsque je clique sur mes liens, ils ne m'amènent pas aux ancres en scrollant et j'ai toujours pas de décalage de -40. :/
Je trouve ce commentaire pertinent ?
merci je commence à comprendre une notion que j'appliquais sans trop comprendre.
Merci!!!!bien expliqué
Je trouve ce commentaire pertinent ?
Je trouve ce commentaire pertinent ?