Perché il mio menu hamburger si apre solo al secondo clic?
In una frase: se ha attivato un JavaScript delay (caricamento degli script al primo clic o dopo un timer), il primissimo tocco sull'hamburger risveglia il caricamento degli script, non apre il menu. Il menu risponde solo al secondo tocco. La soluzione: isolare lo script del menu e le sue dipendenze dal delay, oppure, meglio ancora, dotarlo di un menu vanilla senza dipendenze.
Tocca l'hamburger: niente. Tocca di nuovo: il menu si apre. Ogni singola volta, ci vogliono due tocchi. Non è né casuale né un bug del tema: è il comportamento meccanico del “JavaScript delay”, un'ottimizzazione molto comune. Ecco perché, e i due modi per risolverlo.
Cosa fa il “JavaScript delay” (e perché il primo clic va perso)
Per guadagnare punti di performance, il “JS delay” (o “load on interaction”) posticipa l'esecuzione degli script finché il visitatore non fa qualcosa: uno scroll, un movimento del mouse o un primo tocco. Finché nessuno si muove, nessun JavaScript viene eseguito, e il punteggio iniziale sale.
Il problema è evidente non appena ci si pensa: il primissimo tocco sull'hamburger È proprio quella prima interazione. Quindi quel tocco non apre il menu, ne innesca il caricamento degli script. Quando questi arrivano e si agganciano al pulsante, il dito è già andato via. Il menu si apre solo al secondo tocco, quando lo script è finalmente presente e in ascolto.
Tocco 1 → niente
Il tocco viene “consumato” per avviare il caricamento dello script, non per aprire il menu.
Tocco 2 → il menu si apre
Gli script sono finalmente caricati e il gestore è ora in ascolto sul pulsante.
È ancora più evidente nella variante a timer: se gli script si caricano “dopo 3 secondi”, un visitatore che tocca prima si trova davanti un hamburger morto.
Confermare che si tratta proprio di questo (30 secondi)
Tre verifiche semplici:
- Il sintomo è costante, non intermittente: sono sempre due tocchi. Un vero bug sarebbe più erratico.
- Scheda Network di DevTools: ricaricare, non toccare nulla e osservare. Gli script del menu (spesso jQuery + lo script del tema) si scaricano solo dopo la prima interazione. È questa la firma del delay.
- Test di eliminazione: disattivare temporaneamente il JS delay. Se l'hamburger risponde al primo tocco, il colpevole è identificato.
Soluzione A: isolare il menu E le sue dipendenze
La reazione naturale è escludere lo script del menu dal delay. È necessario, ma spesso non basta, ed è qui che la maggior parte delle persone resta bloccata.
Un menu del tema quasi non funziona mai da solo: dipende da altri script, tipicamente jQuery (e a volte jQuery Migrate, o il core del tema). Se si esclude lo script del menu ma si lascia jQuery nel delay, lo script del menu viene eseguito mentre jQuery non esiste ancora: fallisce silenziosamente o si aggancia al nulla. Risultato: il menu resta rotto, e non se ne capisce il motivo, dato che “il menu è escluso”.
Bisogna quindi escludere l'intera catena: jQuery → (jQuery Migrate) → lo script del menu. Insieme.
Due trappole concrete quando si dichiarano queste esclusioni:
- Individuare tramite un frammento univoco dell'URL del file (per esempio
jquery.min.jso il nome dello script del tema), non tramite il suo “handle” interno: a seconda dello strumento, il suffisso tecnico può essere rimosso e l'esclusione manca il bersaglio. - Mantenere un controllo sullo stato del documento: lo script escluso deve tollerare un'esecuzione anticipata (verificare che il DOM sia pronto prima di agganciarsi al pulsante).
Il compromesso da accettare: togliendo jQuery e il menu dal delay, si ricarica parte del JavaScript in anticipo, quindi si perde parte del guadagno di performance. È accettabile se si vuole mantenere il menu del tema così com'è, ma non è gratis.
Soluzione B (il caso migliore): un menu vanilla, senza dipendenze
La vera soluzione duratura, soprattutto su un tema pesante (Divi, per esempio, dove è il menu a forzare jQuery), è smettere del tutto di far dipendere il menu da jQuery.
Un menu hamburger, in fondo, è banale: un pulsante che alterna una classe sulla navigazione. Bastano poche righe di JavaScript nativo, senza alcuna dipendenza:
<button class="nav-toggle" aria-expanded="false" aria-controls="site-nav">Menu</button>
<nav id="site-nav" class="site-nav"><!-- links --></nav>
<script>
const btn = document.querySelector('.nav-toggle');
const nav = document.getElementById('site-nav');
btn.addEventListener('click', function () {
const open = nav.classList.toggle('is-open');
btn.setAttribute('aria-expanded', open);
});
</script>Poiché questo script è minuscolo e privo di dipendenze, si aprono due opzioni:
- lo si inserisce inline così com'è, non differito, nel tema: l'hamburger risponde al primo tocco, sempre;
- e si può quindi differire assolutamente tutto il resto del proprio JavaScript con tranquillità, dato che l'unica interazione critica (l'apertura del menu) non dipende più da nulla.
Un vantaggio non trascurabile: su molti temi, il menu è l'unico motivo per cui jQuery si carica con priorità. Un menu vanilla può quindi permettere di togliere jQuery dal percorso critico del tutto. È il meglio dei due mondi: un menu istantaneo e un JavaScript più leggero.
Con Mantys Core
Mantys Core gestisce con precisione entrambe le strade. Per la soluzione A, le sue eccezioni al delay vengono dichiarate tramite un frammento di URL (non il fragile handle) e tengono conto della catena di dipendenze, con il controllo sullo stato del documento che fa sì che l'esclusione tenga davvero, invece di fallire silenziosamente.
E per la soluzione B, l'approccio “blocco autosufficiente, non differito” è nativo: un menu vanilla può essere servito fuori dal delay mentre tutto il resto del JavaScript viene posticipato, senza dover destreggiarsi tra punteggio e funzionalità.
In altre parole: che si mantenga il menu del tema o si passi al vanilla, l'hamburger risponde al primo tocco, senza sacrificare l'alleggerimento del resto.
In sintesi
- Il “secondo clic obbligatorio” deriva dal JS delay: il primo tocco risveglia il caricamento degli script invece di aprire il menu.
- Confermarlo osservando che gli script si caricano solo dopo la prima interazione (o disattivando il delay).
- Soluzione A: escludere dal delay il menu E le sue dipendenze (jQuery incluso), puntando tramite URL, con un controllo di stato. Funziona, ma costa parte del guadagno.
- Soluzione B (il caso migliore): un menu vanilla senza dipendenze, inline e non differito, che risponde al primo tocco e permette di differire tutto il resto, jQuery incluso.