Skip to content

Tutto per WordPress, lo sviluppo web — e non solo

🖱 Scorrimento fluido all'ancora: CSS, JavaScript e jQuery - tre approcci funzionanti

🖱 Scorrimento fluido all'ancora: CSS, JavaScript e jQuery - tre approcci funzionanti

L'utente clicca un link con un'ancora e la pagina salta istantaneamente alla destinazione. Nessuna animazione, nessuna fluidità, nessuna comprensione di dove si è atterrati. La transizione brusca è disorientante, specialmente su landing page lunghe e documentazione.

Aggiungere lo smooth scroll alle ancore richiede 5 minuti. Ma il diavolo sta nei dettagli: il link potrebbe provenire da un sito esterno, l'URL ha già un hash e c'è un header fisso in alto che copre l'ancora. La semplice proprietà scroll-behavior: smooth non risolve queste sfumature.

Ecco tre approcci funzionanti: CSS puro, JavaScript nativo e jQuery. Ognuno con codice che puoi copiare e incollare nel tuo progetto. In più, trattiamo separatamente le transizioni esterne, così lo scorrimento funziona anche quando l'utente arriva da un'altra pagina o dai risultati di ricerca.

💡 Panoramica rapida:

  • Abilita lo smooth scroll con una riga CSS, senza JavaScript
  • Aggiungi un offset per l'header fisso usando scroll-margin-top
  • Scrivi JS nativo con scrollIntoView per transizioni esterne e regolazioni fini
  • Copri la variante jQuery con animate() quando servono velocità e controllo personalizzati
  • Gestisci l'hash esterno: pagina caricata, ancora nell'URL e scorrimento fluido fino al target

Perché lo smooth scroll è importante

Un salto brusco a un'ancora è disorientante. L'utente perde il contesto: dov'ero, dove sono atterrato, cosa mi sono perso? Lo smooth scrolling mantiene l'orientamento spaziale, dando all'occhio qualcosa da seguire mentre la pagina si muove.

Dal punto di vista percettivo, un sito con smooth scroll appare curato. Questo è particolarmente evidente sulle pagine lunghe: landing page, documentazione, sezioni FAQ, indici di articoli. L'utente clicca "Prezzi" nel menu e la pagina non scatta ma scivola delicatamente fino al blocco prezzi.

Tecnicamente, il compito si divide in due: scorrimento al clic di un link interno (l'utente è già sulla pagina) e scorrimento in caso di transizione esterna (l'URL contiene già #anchor). Nel secondo caso, il browser di default salta all'ancora istantaneamente ancora prima del caricamento completo, e questo va intercettato.

CSS scroll-behavior, una riga invece di uno script

L'approccio più semplice e moderno. I browser hanno imparato lo smooth scroll in modo nativo, basta una sola regola CSS:

1html {
2 scroll-behavior: smooth;
3}

Tutto qui. Qualsiasi transizione tramite link ad ancora diventa fluida. Niente JavaScript, niente librerie.

Supporto: tutti i browser moderni dal 2022: Chrome 61+, Firefox 36+, Safari 15.4+, Edge 79+. L'unica eccezione è IE11, ma la sua quota di traffico è prossima allo zero.

Header fisso: scroll-margin-top

Se un header fisso (sticky header) sovrasta il contenuto, l'ancora dopo lo scorrimento finirà sotto di esso. Si risolve con una riga:

1h2, h3, [id] {
2 scroll-margin-top: 80px; /* header height + offset */
3}

Il browser aggiungerà automaticamente l'offset quando scorre fino all'elemento target. Prima si scrivevano hack con padding-top e margin negativo, ora non servono più.

Limitazioni del CSS puro

L'approccio CSS non ha controllo sulla velocità dell'animazione e sulla funzione di easing. Il browser usa una curva predefinita, di solito ease-in-out. Se ti servono velocità personalizzata o animazione non lineare, passa a JavaScript.

JavaScript nativo: scrollIntoView

Quando il solo CSS non basta, viene in soccorso il metodo scrollIntoView() con l'opzione behavior: 'smooth':

1document.querySelectorAll('a[href^="#"]').forEach(anchor => {
2 anchor.addEventListener('click', function(e) {
3 e.preventDefault();
4 const target = document.querySelector(this.getAttribute('href'));
5 if (target) {
6 target.scrollIntoView({
7 behavior: 'smooth',
8 block: 'start'
9 });
10 }
11 });
12});

Questo codice intercetta i clic su tutti i link con #, annulla la transizione standard e avvia lo smooth scroll. Funziona senza jQuery e senza librerie aggiuntive.

Il vantaggio: puoi controllarlo programmaticamente: cambiare la velocità tramite scroll-behavior su <html>, aggiungere condizioni (per esempio, escludere certi link), combinarlo con scroll-margin-top per l'header.

Lo svantaggio: scrollIntoView non permette di impostare direttamente la velocità dell'animazione. Per un tempo di scorrimento personalizzato (diciamo 800 ms invece dei ~500 ms del browser) ti serve jQuery o un requestAnimationFrame manuale.

JQuery animate, controllo totale sull'animazione

Se il progetto usa già jQuery o hai bisogno di regolazione fine (velocità, offset per l'header, filtraggio dei link), ecco lo script aggiornato. Di seguito una versione adattata dell'approccio classico, riscritta per jQuery moderno:

1jQuery(document).ready(function($) {
2 // Smooth scroll on anchor link click
3 $('a[href*="#"]:not([href="#"])').on('click', function() {
4 if (
5 location.pathname.replace(/^\//, '') === this.pathname.replace(/^\//, '')
6 && location.hostname === this.hostname
7 ) {
8 var target = $(this.hash);
9 target = target.length ? target : $('[name="' + this.hash.slice(1) + '"]');
10 if (target.length) {
11 $('html, body').animate({
12 scrollTop: target.offset().top - 80
13 }, 800);
14 return false;
15 }
16 }
17 });
18
19 // Scroll on external transition with hash in URL
20 if (window.location.hash) {
21 var hash = window.location.hash.substring(1);
22 var $target = $('#' + hash);
23 if ($target.length) {
24 setTimeout(function() {
25 $('html, body').animate({
26 scrollTop: $target.offset().top - 80
27 }, 800);
28 }, 100);
29 }
30 }
31});

Cosa è cambiato qui rispetto alle vecchie versioni che circolano nei blog:

  • .bind() sostituito con .on(), .bind() è stato dichiarato deprecato in jQuery 3.0 e sarà rimosso in jQuery 4.0.
  • Selettore 'a:not(.spu-clickable)[href*="#"]:not([href="#"])' semplificato, la classe specifica .spu-clickable era legata a un plugin specifico (Popups by OptinMonster) e generalmente non serve.
  • jQuery(window).bind("load", ...) rimosso, la seconda parte dello script per l'hash esterno ora risiede in $(document).ready() e non richiede un evento load separato.
  • Aggiunto ritardo setTimeout(..., 100) così il DOM è garantito essere renderizzato prima di calcolare la posizione dell'ancora (rilevante per pagine con lazy loading di immagini e contenuti dinamici).

Dove inserire il codice

Tre opzioni tra cui scegliere:

  • Tramite file del tema. Aggiungi lo script a functions.php via wp_enqueue_script(), il metodo standard per un child theme.
  • Plugin Code Snippets. Inserisci il codice come nuovo snippet con esecuzione automatica, non andrà perso con l'aggiornamento del tema.
  • Plugin JS personalizzato. Se il sito usa già un plugin per inserire JavaScript arbitrario (per esempio, WPCode), aggiungi il codice lì.

Gestire la transizione esterna con hash, analisi dettagliata

La parte più delicata del compito. L'utente segue un link https://site.com/page/#pricing da un altro sito o dalla ricerca. Il browser di default salta istantaneamente a #pricing non appena l'elemento appare nel DOM, senza animazione e spesso prima che la pagina sia completamente caricata.

Lo script jQuery qui sopra risolve il problema in due passaggi:

  • Rileva la presenza dell'hash tramite window.location.hash. Se l'hash esiste, ne legge il valore (senza #).
  • Trova il target e scorre. $('#' + hash) trova l'elemento, setTimeout dà alla pagina il tempo di renderizzare, animate() porta al target con un offset di 80 pixel.

Il ritardo di 100 millisecondi è empirico. Su pagine veloci bastano 50 ms, su quelle pesanti (landing page con video di sfondo, mappe, grafici) è meglio aumentare a 200-300 ms. Alternativa: attendere l'evento window.load invece di document.ready, ma così lo scorrimento avverrà solo dopo il caricamento di tutte le immagini, il che può richiedere tempo.

Cosa fare se l'ancora non trova il target

A volte l'hash nell'URL punta a un elemento inesistente. Per esempio, l'utente ha fatto un errore di battitura o la pagina è stata modificata. In questo caso, né l'approccio CSS né quello JS falliranno con un errore, semplicemente non succederà nulla. Il browser ignorerà l'ancora inesistente. Anche lo smooth scroll funzionerà in modo silenzioso (la condizione if (target.length) impedirà di procedere oltre).

Confronto tra i tre approcci

Criterio

CSS scroll-behavior

JS scrollIntoView

jQuery animate

Complessità implementativa

1 riga CSS

10-15 righe JS

25-30 righe JS + jQuery

Controllo velocità

No

No (default browser)

Sì (ms)

Hash esterno

Sì, nativamente

Richiede codice extra

Richiede codice extra

Offset header

scroll-margin-top

scroll-margin-top

Manuale in offset().top

Dipendenze

Nessuna

Nessuna

jQuery 3.x

Supporto browser

96%+

96%+

99%+ (con jQuery)

Per la maggior parte dei progetti moderni, l'approccio CSS è ottimale: una riga, zero dipendenze, performance nativa. Se serve offset per l'header, aggiungi scroll-margin-top. Se servono velocità personalizzata o supporto per browser antichi, jQuery con animate().

Di seguito un video con dimostrazione dal vivo di tutti e tre gli approcci, dal CSS a jQuery:

⁉️🤔 Domande frequenti

Perché lo smooth scroll non funziona sui dispositivi mobili?

In iOS Safari prima della versione 15.4, scroll-behavior: smooth non era supportato. Ora il supporto esiste (Safari 15.4+, marzo 2022). Se lo scroll non funziona su vecchi iPhone, aggiungi un fallback JavaScript con scrollIntoView o requestAnimationFrame. Verifica anche che lo scroll non sia bloccato da overflow: hidden su body, alcuni menu mobile lo impostano all'apertura. A giugno 2026, il supporto globale per scroll-behavior è del 96,3% dei browser (dati Can I Use).

Come fare smooth scroll non verso un'ancora ma verso un elemento arbitrario al clic di un pulsante?

Assegna all'elemento un id e usa lo stesso JavaScript, ma legato a un pulsante invece che a un link ad ancora. Per esempio, pulsante "Torna su": document.querySelector('#back-to-top').addEventListener('click', () => window.scrollTo({ top: 0, behavior: 'smooth' })). Per la variante jQuery: $('#back-to-top').on('click', () => $('html, body').animate({ scrollTop: 0 }, 600)). Nessuna ancora necessaria, scorrimento verso coordinate.

È necessario includere jQuery solo per lo smooth scroll nel 2026?

No. jQuery pesa circa 87 KB in versione minificata (30 KB gzip). Se jQuery non è usato altrove nel sito, includerlo per un solo scroll è irrazionale. Usa l'approccio CSS con scroll-behavior: smooth o scrollIntoView nativo. jQuery è giustificato solo se il sito è già costruito su di esso (temi jQuery, progetti legacy) e vuoi aggiungere lo scroll al codebase esistente.

Si può animare lo scroll con velocità diversa, prima veloce, poi lenta?

Sì, tramite $.animate() con jQuery UI o tramite requestAnimationFrame con una funzione di easing. animate() standard di jQuery usa la funzione linear o swing. Per curve non standard, includi jquery.easing o scrivi il tuo loop su requestAnimationFrame con una funzione di easing personalizzata, per esempio easeInOutQuad. Questo dà pieno controllo su velocità, traiettoria e non richiede librerie esterne.

Come verificare che lo scroll funzioni sulla transizione esterna con hash?

Apri una nuova scheda, incolla l'URL con l'ancora (per esempio, https://yoursite.com/page/#contacts) e premi Invio. La pagina dovrebbe caricarsi e scorrere fluidamente fino al blocco. Seconda opzione: nella console del browser sulla pagina aperta, esegui location.hash = '#contacts'. Se lo scroll è fluido, lo script funziona. Se la pagina è scattata istantaneamente, il gestore dell'hash esterno non è configurato.

Quale approccio scegliere per il tuo progetto

Se il sito è moderno, senza jQuery, CSS scroll-behavior: smooth copre la stragrande maggioranza degli scenari. Una riga, risultato immediato. Aggiungi scroll-margin-top per l'header e hai finito.

Se il sito è su WordPress con jQuery nel tema, script jQuery con animate(). Dà controllo su velocità e offset, gestisce le transizioni esterne, non entra in conflitto con altri plugin.

Se scrivi da zero e non vuoi includere una libreria, nativo scrollIntoView() con gestore dell'hash esterno. La via di mezzo: pulito, veloce, nessuna dipendenza.

Prendi il codice dall'articolo, incollalo nel tuo progetto e verifica la transizione esterna, è l'unico caso facile da trascurare durante i test.