
🔧 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.hashpour 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.
1 jQuery(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 enposition: fixedet 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 soithtml, soitbody, donc nous spécifions les deux pour plus de fiabilité.location.hash = myHash: restaure le hash. Maintenant, la barre d’adresse affiche à nouveau#pricinget 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.
1 jQuery(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 22 jQuery(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:
1 jQuery(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}):
1 jQuery('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:
1 jQuery('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
clickne 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équencelocation.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
headerde votre site et vérifiez saheightdans 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' })ouscroll-behavior: smoothen 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:
1 document.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 utilisebodyet Safari dépend de la version. Spécifier les deux sélecteurs dansanimate()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.



