Skip to content

Tout pour WordPress, le développement web — et plus encore

🔧 JQuery : défilement fluide vers une ancre lors de la navigation depuis une autre page

🔧 JQuery : défilement fluide vers une ancre lors de la navigation depuis une autre page

Vous avez ajouté une ancre à la page, mis #section dans l’URL et vous attendez un défilement fluide. L’utilisateur clique depuis une autre page, le navigateur applique le hash comme prévu… et saute brutalement vers la cible. Pas de défilement. Juste un saut instantané.

Le problème vient du fait que les navigateurs traitent le hash instantanément par défaut, avant que le DOM ne soit complètement prêt et que les scripts aient une chance d’intercepter l’événement. Lorsqu’un utilisateur arrive via un lien externe, votre gestionnaire click ne se déclenche jamais: il n’y a pas eu d’événement clic, seulement une navigation directe par URL.

Nous avons compilé deux solutions jQuery éprouvées: un script de base pour les cas simples et une version avancée avec gestion du clic, prise en charge du chargement de page et prévention des conflits. Les deux sont testées sur des projets réels et fonctionnent avec les versions actuelles de jQuery.

💡 Aperçu rapide:

  • Sauvegardez le hash de l’URL dans une variable temporaire
  • Videz location.hash pour que le navigateur ne saute pas brutalement
  • Faites défiler jusqu’à l’ancre via animate() avec le décalage souhaité
  • Restaurez le hash pour obtenir une URL correcte dans la barre d’adresse

Pourquoi le défilement fluide vers les ancres est important

Lorsqu’un visiteur suit un lien comme site.com/page/#pricing, il s’attend à voir le bloc tarification, pas le haut de la page. Un saut brutal est déroutant: l’utilisateur ne comprend pas où il a atterri ni ce qui précédait. Le défilement fluide fournit le contexte: l’œil capte les sections intermédiaires et le cerveau cartographie le trajet de l’origine à la destination.

Avec la propriété CSS native scroll-behavior: smooth, tout est simple: ajoutez-la à votre feuille de styles et le navigateur défile automatiquement jusqu’à l’ancre. Mais cette approche échoue dès que vous avez besoin d’un décalage personnalisé pour un en-tête fixe. Un décalage de 110 pixels empêche le bloc de glisser sous le header et le positionne exactement là où l’utilisateur l’attend. La solution jQuery vous donne ce contrôle.

Il y a aussi la compatibilité entre navigateurs. scroll-behavior: smooth ne fonctionne pas dans Internet Explorer (oui, de tels projets existent encore), tandis que la méthode jQuery animate() se comporte de manière identique partout.

Script de base: code minimal, bénéfice maximal

La première option est compacte, seulement 10 lignes. Elle résout exactement un problème: faire défiler en douceur jusqu’à une ancre lorsque l’utilisateur arrive d’une autre page ou via un lien direct avec un hash.

1jQuery(document).ready(function ($) {
2 var myHash = location.hash; // save the hash
3 location.hash = ''; // clear it — browser stops jerking
4 if (myHash[1] != undefined) { // hash not empty?
5 $('html, body').animate(
6 { scrollTop: $(myHash).offset().top - 110 },
7 700 // duration in milliseconds
8 );
9 location.hash = myHash; // restore the hash
10 }
11});

Décomposition étape par étape, car trois lignes font des merveilles, mais comprendre la mécanique est important:

  • var myHash = location.hash: lit le hash depuis la barre d’adresse (par exemple, #pricing). À ce stade, le navigateur n’a pas encore défilé.
  • location.hash = '': l’astuce clé. Vider le hash fait perdre au navigateur sa cible pour le saut instantané. Sans cette ligne, le script «lutterait» contre le comportement natif du navigateur et perdrait.
  • $(myHash).offset().top - 110: calcule la position de l’ancre par rapport au haut du document et soustrait 110 pixels. C’est votre décalage pour un en-tête fixe. Si votre en-tête est en position: fixed et mesure 80px de haut, utilisez 80 (ou 90 pour un peu de marge). S’il n’y a pas d’en-tête, supprimez complètement la soustraction.
  • $('html, body').animate(...): fait défiler en douceur sur 700 millisecondes. Le sélecteur 'html, body' n’est pas un caprice: différents navigateurs font défiler soit html, soit body, donc nous spécifions les deux pour plus de fiabilité.
  • location.hash = myHash: restaure le hash. Maintenant, la barre d’adresse affiche à nouveau #pricing et la page est déjà positionnée proprement sur le bloc cible.

Insérez le script dans le fichier functions.php de votre thème, un fichier JS personnalisé ou via un plugin comme Code Snippets. L’exigence clé est qu’il doit se trouver à l’intérieur d’un bloc jQuery(document).ready().

Version avancée: gestion du clic, chargement de page et protection contre les conflits

Le script de base couvre la plupart des scénarios, mais parfois location.hash = '' ne fonctionne pas à temps: le navigateur saute avant que le hash ne soit vidé. Dans ces cas, utilisez la deuxième version. Elle est plus lourde mais plus fiable.

1jQuery(document).ready(function () {
2 jQuery(window).bind('load', function () {
3 jQuery('a:not(.spu-clickable)[href*="#"]:not([href="#"])').click(function () {
4 if (
5 location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') ||
6 location.hostname == this.hostname
7 ) {
8 var target = jQuery(this.hash);
9 target = target.length ? target : jQuery('[name=' + this.hash.slice(1) + ']');
10 if (target.length) {
11 jQuery('html, body').animate(
12 { scrollTop: target.offset().top - 37 },
13 1000
14 );
15 return false;
16 }
17 }
18 });
19 });
20});
21
22jQuery(window).load(function () {
23 function goToByScroll(id) {
24 jQuery('html, body').animate(
25 { scrollTop: jQuery('#' + id).offset().top - 38 },
26 1000
27 );
28 }
29 if (window.location.hash != '') {
30 goToByScroll(window.location.hash.substr(1));
31 }
32});

Voici ce qui se passe, bloc par bloc:

Bloc un: un gestionnaire de clic pour les liens d’ancrage internes. jQuery(window).bind('load', ...) garantit que tous les éléments de la page (y compris les images et les iframes) sont chargés avant de lier le gestionnaire. Le filtre a:not(.spu-clickable) exclut les liens déjà gérés par un plugin de popup (SPU, WordPress PopUp), évitant les conflits d’animation. Ajoutez vos propres classes d’exclusion en suivant le même modèle.

Bloc deux: gestion de la navigation depuis une page externe. jQuery(window).load() se déclenche plus tard que document.ready et garantit que tous les éléments, y compris l’ancre, sont dans le DOM. La fonction goToByScroll(id) fait exactement ce que fait le script de base, mais n’est appelée qu’après le chargement complet de la fenêtre. substr(1) supprime le caractère # du hash.

Remarque importante: jQuery(window).load() est déprécié depuis jQuery 3.0. Si votre projet utilise une version actuelle de jQuery, remplacez-le par:

1jQuery(window).on('load', function () {
2 // code here
3});

La syntaxe diffère, mais le comportement est identique.

Réglages fins: décalages, sélecteurs et pièges à éviter

Le script fonctionne, mais chaque mise en page est unique. Voici trois ajustements courants qui ont sauvé des projets réels.

Problème un: offset().top renvoie des coordonnées incorrectes. Cela se produit lorsque des éléments parents ont les propriétés CSS transform, filter ou will-change, qui créent un nouveau contexte de positionnement. offset() calcule alors par rapport à ce contexte plutôt qu’au document. Solution: utilisez offset({top: -0}):

1jQuery('html, body').animate(
2 { scrollTop: jQuery('#' + id).offset({ top: -0 }).top },
3 1000
4);

Le paramètre {top: -0} force jQuery à recalculer la position depuis les limites du document, en ignorant les contextes intermédiaires. Cela ressemble à de la magie, mais cela fonctionne.

Problème deux: le sélecteur 'html, body' fait défiler le mauvais élément. Dans certains thèmes, le conteneur de défilement n’est pas html ou body mais un bloc spécifique, par exemple body.home pour la page d’accueil ou .main-content pour les pages intérieures. Identifiez votre conteneur via les DevTools (onglet Éléments → recherchez overflow: scroll ou overflow: auto) et remplacez-le dans le sélecteur:

1jQuery('body.home').animate(
2 { scrollTop: target.offset().top - 37 },
3 1000
4);

Problème trois: le hash contient des caractères cyrilliques ou spéciaux. location.hash renvoie une séquence encodée URL au lieu d’une chaîne lisible, et le sélecteur jQuery $(myHash) ne trouvera pas l’élément. Solution: décodez le hash avec decodeURIComponent() avant de l’utiliser dans le sélecteur.

Vidéo: exemple en direct de défilement depuis un lien externe

Une courte démonstration de John Smith: défilement fluide vers une ancre via jQuery animate() sur une page réelle avec un en-tête fixe et une navigation externe.

⁉️🤔 Foire aux questions

Le script fonctionne sur la même page mais pas lors de la navigation depuis une autre URL. Pourquoi?

Parce que le gestionnaire click ne se déclenche jamais: il n’y a pas eu de clic. L’utilisateur a suivi un lien direct et le navigateur a traité le hash avant que votre JS ne s’exécute. La solution est la séquence location.hash = '' + animate() + location.hash = myHash. Vider le hash annule le saut natif, l’animation défile en douceur et la restauration du hash préserve l’URL correcte dans la barre d’adresse.

Quel décalage dois-je utiliser pour un en-tête fixe?

La hauteur exacte de l’en-tête plus quelques pixels de marge. Ouvrez les DevTools (F12), sélectionnez l’élément header de votre site et vérifiez sa height dans l’onglet Computed. Par exemple, si l’en-tête fait 80px, utilisez 90 dans votre code. Si la version mobile a une hauteur d’en-tête différente, ajoutez une media query avec un calcul de décalage dynamique.

jQuery est-il encore pertinent en 2026?

Oui, en particulier dans l’écosystème WordPress. jQuery reste dans le cœur de WP, de nombreux plugins et thèmes en dépendent, et la migration de tout l’écosystème vers du JS natif prendra des années. Pour les nouveaux projets en JavaScript pur, le défilement fluide se fait via element.scrollIntoView({ behavior: 'smooth' }) ou scroll-behavior: smooth en CSS, avec beaucoup moins de lignes de code. Mais si vous modifiez un site WP existant, la solution jQuery reste fiable et appropriée.

Puis-je éviter complètement jQuery?

Vous le pouvez et vous le devriez, si le projet est nouveau. L’équivalent natif du script de base:

1document.addEventListener('DOMContentLoaded', () => {
2 const hash = window.location.hash;
3 if (hash) {
4 window.location.hash = '';
5 const target = document.querySelector(hash);
6 if (target) {
7 window.scrollTo({
8 top: target.getBoundingClientRect().top + window.pageYOffset - 110,
9 behavior: 'smooth'
10 });
11 }
12 window.location.hash = hash;
13 }
14});

Même principe: sauvegardez le hash, videz-le, faites défiler, restaurez-le. La différence est que behavior: 'smooth' utilise le moteur CSS natif du navigateur plutôt qu’un timer jQuery. Vous ne pouvez pas configurer la vitesse, mais le code est plus léger de 30 Ko (le poids de jQuery).

Pourquoi $('html, body') au lieu de simplement $('html')?

Firefox fait défiler html, Chrome utilise body et Safari dépend de la version. Spécifier les deux sélecteurs dans animate() garantit que cela fonctionne sur tous les navigateurs: jQuery envoie l’animation à l’élément qui l’applique effectivement.

Vaut-il la peine d’utiliser jQuery uniquement pour le défilement fluide en 2026

Si vous avez un site WordPress ou un projet legacy où jQuery est déjà chargé, prenez le script de cet article et ne compliquez pas les choses. Dix lignes de code qui fonctionnent partout, dans tous les navigateurs, sans polyfills requis. Pour les nouveaux projets en JavaScript pur, utilisez le scroll-behavior: smooth natif ou scrollIntoView(). Les deux approches produisent un défilement fluide, mais la méthode jQuery vous donne le contrôle sur la vitesse, le décalage et le sélecteur du conteneur de défilement. Les implémentations natives nécessitent des vérifications séparées pour obtenir le même résultat.

La règle principale que nous avons apprise de dizaines de projets: videz toujours le hash avant de faire défiler. Sans cette astuce, aucun gestionnaire ne peut battre le comportement natif du navigateur et les utilisateurs continueront de subir des sauts brutaux.