Skip to content

Tutto per WordPress, lo sviluppo web — e non solo

🔧 JQuery: scorrimento fluido all'ancora quando si naviga da un'altra pagina

🔧 JQuery: scorrimento fluido all'ancora quando si naviga da un'altra pagina

Hai aggiunto un'ancora alla pagina, inserito #section nell'URL e ti aspetti uno scorrimento fluido e piacevole. L'utente clicca da un'altra pagina, il browser applica diligentemente l'hash... e scatta bruscamente verso il target. Nessuno scorrimento. Solo un salto istantaneo.

Il problema è che i browser gestiscono l'hash all'istante per impostazione predefinita, prima che il DOM sia completamente pronto e che gli script abbiano la possibilità di intercettare l'evento. Quando un utente arriva tramite un link esterno, il tuo gestore click non viene mai attivato: non c'è stato alcun evento click, solo una navigazione diretta tramite URL.

Abbiamo raccolto due soluzioni jQuery collaudate sul campo: uno script base per casi semplici e una versione avanzata con gestione del click, supporto per il caricamento della pagina ed evitamento dei conflitti. Entrambe sono testate su progetti reali e funzionano con le versioni attuali di jQuery.

💡 Panoramica rapida:

  • Salva l'hash dall'URL in una variabile temporanea
  • Pulisci location.hash così che il browser non salti bruscamente
  • Scorri fino all'ancora tramite animate() con l'offset desiderato
  • Ripristina l'hash per avere un URL corretto nella barra degli indirizzi

Perché lo scorrimento fluido delle ancore è importante

Quando un visitatore segue un link come site.com/page/#pricing, si aspetta di vedere il blocco prezzi, non la cima della pagina. Un salto brusco è disorientante: l'utente non capisce dove è atterrato né cosa c'era prima. Lo scorrimento fluido fornisce contesto: gli occhi colgono le sezioni intermedie e il cervello mappa il percorso dall'origine alla destinazione.

Con la proprietà CSS nativa scroll-behavior: smooth, le cose sono semplici: la aggiungi al tuo foglio di stile e il browser scorre automaticamente fino all'ancora. Ma questo approccio si rompe nel momento in cui hai bisogno di un offset personalizzato per un header fisso. Un offset di 110 pixel impedisce al blocco di scivolare sotto l'header e lo posiziona esattamente dove l'utente si aspetta. La soluzione jQuery ti dà questo controllo.

C'è anche la questione della compatibilità cross-browser. scroll-behavior: smooth non funziona in Internet Explorer (sì, esistono ancora progetti del genere), mentre il metodo animate() di jQuery si comporta in modo identico ovunque.

Script base: codice minimo, massimo beneficio

La prima opzione è compatta, solo 10 righe. Risolve esattamente un problema: scorrere fluidamente fino a un'ancora quando l'utente arriva da un'altra pagina o tramite un link diretto con 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});

Analisi passo passo, perché tre righe fanno magie, ma capire i meccanismi è importante:

  • var myHash = location.hash: legge l'hash dalla barra degli indirizzi (ad esempio, #pricing). A questo punto il browser non ha ancora effettuato lo scorrimento.
  • location.hash = '': il trucco chiave. Pulire l'hash fa sì che il browser perda il suo target per il salto istantaneo. Senza questa riga lo script "combatterebbe" contro il comportamento predefinito del browser e perderebbe.
  • $(myHash).offset().top - 110: calcola la posizione dell'ancora dalla cima del documento e sottrae 110 pixel. Questo è il tuo offset per un header fisso. Se il tuo header è position: fixed e alto 80px, usa 80 (o 90 per un po' di respiro). Se non c'è un header, rimuovi del tutto la sottrazione.
  • $('html, body').animate(...): scorre fluidamente in 700 millisecondi. Il selettore 'html, body' non è un capriccio: browser diversi fanno scorrere o html o body, quindi li specifichiamo entrambi per affidabilità.
  • location.hash = myHash: ripristina l'hash. Ora la barra degli indirizzi mostra di nuovo #pricing e la pagina è già parcheggiata ordinatamente sul blocco target.

Inserisci lo script nel functions.php del tuo tema, in un file JS personalizzato o tramite un plugin come Code Snippets. Il requisito fondamentale è che deve trovarsi all'interno di un blocco jQuery(document).ready().

Versione avanzata: gestione del click, caricamento pagina e protezione dai conflitti

Lo script base copre la maggior parte degli scenari, ma a volte location.hash = '' non funziona in tempo: il browser salta prima che l'hash venga pulito. In questi casi, usa la seconda versione. È più pesante ma più affidabile.

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});

Ecco cosa succede, blocco per blocco:

Blocco uno: un gestore di click per i link interni con ancora. jQuery(window).bind('load', ...) assicura che tutti gli elementi della pagina (incluse immagini e iframe) siano caricati prima di associare il gestore. Il filtro a:not(.spu-clickable) esclude i link già gestiti da un plugin popup (SPU, WordPress PopUp), prevenendo conflitti di animazione. Aggiungi le tue classi di esclusione seguendo lo stesso schema.

Blocco due: gestione della navigazione da una pagina esterna. jQuery(window).load() si attiva dopo document.ready e garantisce che tutti gli elementi, inclusa l'ancora, siano nel DOM. La funzione goToByScroll(id) fa esattamente ciò che fa lo script base, ma viene chiamata solo dopo che la finestra è completamente caricata. substr(1) rimuove il carattere # dall'hash.

Nota importante: jQuery(window).load() è deprecato a partire da jQuery 3.0. Se il tuo progetto utilizza una versione corrente di jQuery, sostituiscilo con:

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

La sintassi è diversa, ma il comportamento è identico.

Messa a punto: offset, selettori e insidie

Lo script funziona, ma ogni layout è unico. Ecco tre modifiche comuni che hanno salvato progetti reali.

Problema uno: offset().top restituisce coordinate errate. Questo accade quando gli elementi genitori hanno le proprietà CSS transform, filter o will-change, che creano un nuovo contesto di posizionamento. offset() quindi calcola relativamente a quel contesto invece che al documento. Soluzione: usa offset({top: -0}):

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

Il parametro {top: -0} forza jQuery a ricalcolare la posizione dai confini del documento, ignorando i contesti intermedi. Sembra magia, ma funziona.

Problema due: il selettore 'html, body' fa scorrere l'elemento sbagliato. In alcuni temi il contenitore dello scorrimento non è html o body ma un blocco specifico, ad esempio body.home per la home page o .main-content per le pagine interne. Identifica il tuo contenitore tramite DevTools (scheda Elementi → cerca overflow: scroll o overflow: auto) e sostituiscilo nel selettore:

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

Problema tre: l'hash contiene caratteri cirillici o speciali. location.hash restituisce una sequenza codificata in URL invece di una stringa leggibile, e il selettore jQuery $(myHash) non troverà l'elemento. Soluzione: decodifica l'hash con decodeURIComponent() prima di usarlo nel selettore.

Una breve demo da John Smith: scorrimento fluido delle ancore tramite animate() di jQuery su una pagina reale con header fisso e navigazione esterna.

⁉️🤔 Domande frequenti

Lo script funziona sulla stessa pagina ma non quando si naviga da un altro URL. Perché?

Perché il gestore click non viene mai attivato: non c'è stato alcun click. L'utente ha seguito un link diretto e il browser ha elaborato l'hash prima che il tuo JS venisse eseguito. La soluzione è la sequenza location.hash = '' + animate() + location.hash = myHash. Pulire l'hash annulla il salto predefinito, l'animazione scorre fluidamente e ripristinare l'hash conserva l'URL corretto nella barra degli indirizzi.

Che offset dovrei usare per un header fisso?

L'altezza esatta dell'header più qualche pixel di respiro. Apri DevTools (F12), seleziona l'elemento header del tuo sito e controlla la sua height nella scheda Computed. Ad esempio, se l'header è di 80px, usa 90 nel tuo codice. Se la versione mobile ha un'altezza dell'header diversa, aggiungi una media query con un calcolo dinamico dell'offset.

jQuery è ancora rilevante nel 2026?

Sì, specialmente nell'ecosistema WordPress. jQuery rimane nel core di WP, molti plugin e temi ne dipendono e migrare l'intero ecosistema a JS nativo richiederà anni. Per nuovi progetti in JavaScript puro, lo scorrimento fluido si fa tramite element.scrollIntoView({ behavior: 'smooth' }) o scroll-behavior: smooth nei CSS, con molte meno righe di codice. Ma se stai modificando un sito WP esistente, la soluzione jQuery è ancora affidabile e appropriata.

Posso evitare del tutto jQuery?

Puoi e dovresti, se il progetto è nuovo. L'equivalente nativo dello script 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});

Stesso principio: salva l'hash, puliscilo, scorri, ripristinalo. La differenza è che behavior: 'smooth' usa il motore CSS nativo del browser invece di un timer jQuery. Non puoi configurare la velocità, ma il codice è 30 KB più leggero (il peso di jQuery).

Perché $('html, body') invece di solo $('html')?

Firefox fa scorrere html, Chrome usa body e Safari dipende dalla versione. Specificare entrambi i selettori in animate() garantisce che funzioni su tutti i browser: jQuery invia l'animazione all'elemento che effettivamente la applica.

Vale la pena usare jQuery solo per lo scorrimento fluido nel 2026

Se hai un sito WordPress o un progetto legacy dove jQuery è già caricato, prendi lo script da questo articolo e non complicare le cose. Dieci righe di codice che funzionano ovunque, in qualsiasi browser, senza bisogno di polyfill. Per nuovi sviluppi in JavaScript puro, usa il nativo scroll-behavior: smooth o scrollIntoView(). Entrambi gli approcci producono uno scorrimento fluido, ma il metodo jQuery ti dà controllo su velocità, offset e selettore del contenitore di scorrimento. Le implementazioni native richiedono controlli separati per ottenere lo stesso risultato.

La regola principale che abbiamo imparato da dozzine di progetti: pulisci sempre l'hash prima di scorrere. Senza questo trucco nessun gestore può battere il comportamento predefinito del browser e gli utenti continueranno a sperimentare salti bruschi.