
🖱 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
scrollIntoViewper 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:
1 html { 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:
1 h2, 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':
1 document.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:
1 jQuery(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-clickableera 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 eventoloadseparato.- 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.phpviawp_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,setTimeoutdà 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 |
|
| Manuale in |
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: smoothnon era supportato. Ora il supporto esiste (Safari 15.4+, marzo 2022). Se lo scroll non funziona su vecchi iPhone, aggiungi un fallback JavaScript conscrollIntoVieworequestAnimationFrame. Verifica anche che lo scroll non sia bloccato daoverflow: hiddensubody, alcuni menu mobile lo impostano all'apertura. A giugno 2026, il supporto globale perscroll-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
ide 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: smoothoscrollIntoViewnativo. 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 tramiterequestAnimationFramecon una funzione di easing.animate()standard di jQuery usa la funzione linear o swing. Per curve non standard, includijquery.easingo scrivi il tuo loop surequestAnimationFramecon 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, eseguilocation.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.



