
UPDATE: Ho pubblicato un secondo tutorial in cui ho riportato le modifiche richieste nei feedback, come rendere la voce del menu principale anch’essa cliccabile e poter rimanere aperto il sotto menu corrispondente alla pagina visitata.
In questo tutoriale faremo un semplice menu verticale con jQuery ma che cattura l’attenzione del navigatore con l’aiuto di CSS e del plugin Easing per l’effetto a fisarmonica.
Documento HTML
Come potete vedere in seguito dalla demo, il menu è diviso in quattro voci, ciascuna definita da un elemento LI posizionati all’interno dell’elenco principale UL:
<li class="menu"> <!-- costituisce ogni sezione del menu principale -->
<ul>
<!-- titolo della sezione che fa aprire il sotto menu -->
<li class="title"><a href="#">Categoria Firefox</a></li>
<li class="sub-menu">
<ul>
<li><a href="http://www.mainickweb.com/hack-css-per-firefox-opera-safari-e-internet-explorer/">Articolo 1</a></li>
<li><a href="http://www.mainickweb.com/firefox-3-le-caratteristiche/">Articolo 2</a></li>
</ul>
</li>
</ul>
</li>
Ogni voce del menu contiene un altro elenco UL, formato dalla voce del menu principale (li.title) e da un altro elenco UL che rappresenta il sotto menu (li.sub-menu).
All’interno dell’elemento li.title abbiamo un ancora a cui poi associamo un gestore di eventi jQuery che fa aprire il sotto menu corrispondente: il menu a discesa è nascosto di default tramite la proprietà css display: none.
Foglio di stile CSS
Con uno stile accattivante, anche la più semplice idea può fare una grande differenza nell’attenzione del visitatore.
E’ importante fare particolare attenzione che il codice CSS sia valido e che funzioni bene in tutti i browser:
li.menu {
/* Voci dell'elenco principale */
width: 100%;
padding: 5px 0;
}
li.title a {
/* Voce del menu principale */
display: block;
position: relative;
width: 200px;
height: 34px;
padding: 10px 20px 0;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
background-color: #cc0000;
color: #ffffff;
font-family: BPreplay,Arial,Helvetica,sans-serif;
font-size: 21px;
overflow: hidden;
}
li.title a:hover {
background-color: #f40000;
text-decoration: none;
}
li.title a span {
/* Questo span agisce come parte finale della sezione title */
display: block;
position: absolute;
top: 0;
right: 0;
width: 4px;
height: 44px;
}
.sub-menu {
/* Sotto menu */
display: none;
width: 100%;
padding-top: 5px;
}
.sub-menu li {
/* Voci del sotto menu */
margin: 5px 0;
padding: 4px 18px;
border: 1px solid #40392c;
background-color: #2F2F2F;
color: #cccccc;
}
Effetti con jQuery
In primo luogo abbiamo bisogno di includere alcuni script nel documento HTML (questo codice va messo all’interno della sezione HEAD):
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript" src="jquery.easing.1.3.js"></script> <script type="text/javascript" src="script.js"></script>
Per prima cosa bisogna includere la libreria jQuery (in questo caso dai server di Google), poi il plugin Easing e infine il nostro file di script.
Come potete notare dalla demo, l’effetto che si ha nell’aprire un sotto menu è simile ad un rimbalzo. Questo risultato è ottenuto con l’aiuto del plugin Easing per jQuery: esso prevede una serie di effetti interessanti.
Ecco il codice del nostro file di script:
$(document).ready(function(){
/* Cambiare l'effetto da utilizzare */
$.easing.def = "easeOutBounce";
/* Associare una funzione all'evento click sul link */
$('li.title a').click(function(e){
/* Finding the drop down list that corresponds to the current section: */
var subMenu = $(this).parent().next();
/* Trovare il sotto menu che corrisponde alla voce cliccata */
$('.sub-menu').not(subMenu).slideUp('slow');
subMenu.stop(false,true).slideToggle('slow');
/* Prevenire l'evento predefinito (che sarebbe di seguire il collegamento) */
e.preventDefault();
})
});
Per prima cosa bisogna impostare l’effetto da utilizzare (easeOutBounce), e quindi associare una funzione da compiere per l’evento click sul link in li.title: si ottiene il corrispondente sotto menu (linea ) e lo si mostra (linea ), nascondendo tutti gli altri (linea ).
Il metodo slideToggle di jQuery controlla se l’elemento è già visibile sulla pagina, e decide se mostrarlo o nasconderlo: in questo modo, quando si fa click su una sezione del menu già aperta, essa viene semplicemente chiusa.
Dopo questo, usiamo e.preventDefault() per impedire al browser di seguire il collegamento (il comportamento normale per avere cliccato su un link).











































Ottimo! solo una cosa.. se volessi implementare a:active
per il submenu?
$(document).ready(function() {
$(“.sub-menu a”).click(function() {
$(“.sub-menu a”).removeClass(“selected”);
$(this).addClass(“selected”);
});
});
Grazie!
@ DVD:
scusami ma con
$(this)ti stai riferendo alla voce cliccata, dunque quello che fa ciò che hai scritto è rimuovere la classeselectede poi ri-aggiungerla.Non ho capito cosa cercavi di fare
@ MaiNick:
Praticamente voglio assegnare una classe dei css diversa alla voce del menu selezionata. Per esempio se clicco su Articolo 1, si deve attivare per la voce selezionata una classe specifica che ho definito che lo evidenzia fino a che non seleziono un altra voce.
Grazie!
@ DVD:
forse ho capito. Inserisci nel file di script, dopo la dichiarazione dell’evento click sui link principali:
$('li.sub-menu a').click(function(){// rimuovo la classe css su ogni possibile link voce sotto-menu
$('li.sub-menu a').each(function(){
$(this).removeClass("selected");
});
// aggiungo la classe css al link cliccato
$(this).addClass("selected");
// se non deve continuare nella funzione default del link
return false;
});
spero di aver capito e risolto il tuo problema.
6 un grande! Grazie mille!!
Ciao! Sarebbe grandioso se esistesse anche una versione “orizzontale” di questo fantastico menù. Mi spiego…
invece di avere la progressione così
—-
|
—-
|
—-
e via dicendo, sarebbe possibile averla così:
|—-|–|—–|
o è troppo complicato?
Grazie!
Ciao e complimenti! Senti, come posso fare per mantenere il sotto menu aperto una volta cliccata una voce.
mi spiego meglio:
clicco una una delle voci principali -> si apre la tendina -> clicco su una voce di sotto menu -> vengo indirizzato alla pagina. Ecco, vorrei che nella nuova pagina il sotto menu selezionato in precedenza rimanesse aperto.
grazie
Ciao e grazie! Puoi inviarti un valore tramite l’array globale
$_GET, oppure tramite uno script in JavaScript controllare l’indirizzo della pagina corrente. Tutti e due i casi imposti una classe CSS, ad esempio open, che ti rimane aperto il sotto-menu desiderato.Ciao e grazie per la solerte risposta. Il problema è che il menu si genera dinamicamente attraverso un ciclo while, se invio tramite get un valore x tutti i link del menu avranno quel valore e quindi tutte le tendine si aprirebbero.
Spero di essermi spiegato!
Hai qualche idea?
grazie
@ MaiNick:
@ pino: meglio così, io per valore intendevo la voce del menù che devi visualizzare: quando generi il menu con il
whilefai un controllo se la voce da visualizzare è uguale a quella inviata allora stampa la classeopenHai ragione MaiN, mi ero scioccamente impuntato sulle sottocategorie. Ora funziona, ti ringrazio.
MaiN, come ti dicevo, funziona. C’è solo un piccolo problema:
una volta giunto sulla pagina di destinazione, il sottomenu rimane aperto, appunto. Ma se seleziono un’altra voce di menu, chiaramente il sottomenu precedente continua a rimanere aperto a causa della classe open cui ora è soggetta.
È possibile ri-associare la classe originaria a quel sottomenu quando si fa clic su una nuova voce di menu?
Se ho capito bene dici che se clikki una voce del menu principale, il sotto-menu che prima era aperto tramite la classe
opennon si chiude automaticamente.Allora puoi risolvere il problema inserendo nel codice del file dello script, prima della riga di codice
$('.sub-menu').not(subMenu).slideUp('slow');, la seguente istruzione:$('.sub-menu').not(subMenu).removeClass('open');.Spero di aver capito il tuo problema e di averlo risolto.
Ciao MaiN. Esatto, il problema è proprio questo.
La classe “open” rimane associata a quel che si porta dietro il nome della categoria principale.
Il mio problema è quello di rimuovere la classe “open” e riattivare la classe d’origine “sub-menu”.
Ho provato a inserire l’istruzione che dicevi ma, ahimè, non produce alcun effetto.
Scusami ma la classe
openè sullo stesso elemento a cui è associata la classesub-menu?ho fatto un controllo di questo tipo:
<?php
if($open==$nome_cat) {
$class = "open";
echo "”;
} else {
echo “”;
}
?>
Se scrivi il sotto-menu nel modo seguente, il codice JavaScript che ti ho scritto nei commenti precedenti, dovrebbe funzionare:
<li class="sub-menu <?php echo ($open==$nome_cat) ? 'open' : ''"?>">
<ul>
<li><a href="#">Articolo 1</a></li>
<li><a href="#">Articolo 2</a></li>
</ul>
</li>
scusa, il codice di prima non ha incluso le due opzioni .
Ci riprovo:
<?php
if($open==$nome_cat) {
$class = "open";
echo "”;
} else {
echo “”;
}
?>
di nuovo, provo così:
nel primo echo ci sta
e nel secondo
else
Non funziona. Facendo come dici l’output html mi restituisce questo:
li class=”sub-menu open”
Scusa ma tu prima dove la mettevi la classe
open?con un controllo if else, se variabile open corrisponde a variabile nome_cat allora stampo un “li” con class “open”, altrimenti stampo “li” con class “sub-menu”@ MaiNick:
Quindi se ho capito bene metti la classe
opensuli, dove ci sono i link alle pagine, all’interno della lista con la classesub-menu.Se si al posto del codice javascript che ti ho scritto alcuni commenti prima
$('.sub-menu').not(subMenu).removeClass('open');sostituiscila con la seguente riga$('.sub-menu li').removeClass('open');che non fa altro che togliere la classeopenda tutte le vociliinterne al lista con classesub-menu.Se non funziona inviami un’e-mail risponde a quella che ti ho inviato in questo momento.
MaiNick ha scritto:
so qual è la pagina.. ok! e come dico con i CSS che resti aperto??
Puoi fare come ho scritto in un commento precedente: scrivi il sotto-menu nel modo seguente
<li class="sub-menu <?php echo ($_GET['open']==$nome_cat) ? ‘open’ : ” ?>">
<ul>
<li><a href="#">Articolo 1</a></li>
<li><a href="#">Articolo 2lt;/a></li>
</ul>
&/li>
dove
$nome_catè il nome della categoria o voce lista con il quale fare il confronto con il valore inviato tramite$_GET['open'].Una domanda! (sono un neofita, quindi non lapidatemi
).
Voglio che se JavaScript venga disattivato il menù possa apparire per intero, quindi aperto.
Altrimenti, con JS attivato, chiuso.
Grazie
@ Iron: benvenuto iron.
Allora innanzitutto devi togliere la proprietà
display:nonedi.sub-menudal foglio di stile CSS, poi inserisci la seguente riga di codice javascript nel codice del file di script:$('.sub-menu').css("display","none");subito dopo
$(document).ready(function(){Ciao, complimenti per il blog.
Io, purtroppo ho un problema non posso usare il codice php “> che tu hai indicato.
Mi sarebbe utile capire come indicare tramite il CSS e il Javascript di lasciare aperto il sotto menu.
Grazie per l’attenzione.
@ Fabio: ciao Fabio e grazie dei complimenti.
Se vedi il commento sopra il tuo ho risolto il tuo problema solo con codice JavaScript e CSS.
Grazie MaiNick per la risposta
Un ultimo quesito.
Voglio dare un’effetto diverso dal Bounce.
All’apertura del sub-menu infatti, vorrei dare un effetto di Fade al sub-menu stesso.
Come posso fare?
Grazie ancora
@MaiNick: Grazie sei stato velocissimo. Ma credo di essermi spiegato male: io ho lo stesso problema che aveva Pino, ma posso trovare una soluzione esclusivamente tramite Javascript e CSS.
La tua soluzione può essere un punto di partenza ma devo trovare un modo per lasciare esploso solo il sottomenu inerente al link visitato.
Grazie ancora
@ Iron: dirti la verità non mi piace molto, anche perché non si vedrebbe l’effetto, comunque se vuoi puoi sostituire nel file di script la seguente voce:
subMenu.stop(false,true).slideToggle('slow');con la seguente
subMenu.stop(false,true).fadeIn('slow');Era proprio l’effetto che volevo dare, grazie.
Però una volta aperto un sub-menu, se ri-clicco sulla voce principale il sub-menu stesso non si richiude..
Come potrei risolvere?
Grazie
@MaiNick: secondo me ti sei pentito di questo post
Ti stiamo rompendo proprio l’anima !!!
@ Fabio: come per Pino ti invii un valore tramite url
http://www.esempio.it/articolo.html?catopen=jqueryche poi prelevi tramite JavaScript in questo modo:var categoriaOpen = unescape(self.location.search.substr(1)).split("=");otterrai nella variabile
categoriaOpenun array composto da due elementicategoriaOpen[0]il valorecatopenecategoriaOpen[1]il valore del menu da lasciare apertojquery.Puoi inserire questo codice JavaScript nel file di script dell’esempio e poi continuare con uno
switcho unifper determinare il menu che dovrà avere la classeopenspiegata nei commenti in risposta a Pino.@ Iron: si infatti, perché prima c’era l’effetto
slideToggleche provvedeva ad aprire o chiudere con effetto a tendina a seconda che si trovava nello stato inverso, mentre non esiste un effetto fade che provveda ad eseguire l’effetto inverso allo stato in cui si trova (aperto o chiuso) e deve provvedere tu tramitefadeInefadeOut, ma come è sviluppato il menu è un passaggio piuttosto difficile.Mi dispiace non averti dato una risposta migliore
Iron ha scritto:
PS: dimenticavo! Con un fade anche in chiusura
Ah, letto ora
grazie 1000 delle risposte.
Ciao!
@MaiNick: Grazie 1000. Sei stato davvero gentilissimo!!!
Ciao MainNick, sono un niubbio con javascript e jquery, e sono di fronte ad un prob, che è l’attivazione del controllo activeX di IE (ho la versione 8)..
ho visto che molti esempi e animazioni di Jquery funzionano senza questo prob, ma quando provo a creare una funzione,
e lo testo su IE, mi parte il controllo activeX..
mi è anche venuto un dubbio non è (come in Flash) che il controllo parte quando il file viene testato in locale??
e se è cosi come si fà a vedere effettivamente se usando altre tecnologie javascript e ajax non parta quel controllo quando il sito è online?
grazie..
@ aleandro: ciao e benvenuto. Si il problema che si attivi il controllo ActiveX su IE risulta solo in locale (verifica di sicurezza), mentre on-line non si verificherà.
@ MaiNick:
grazie, mi ci sono sbattuto per diversi giorni..
Ciao. E’ possibile che una voce non apra altre voci ma che sia un link diretto? Come si fa?
@ Riccardo: ciao e benvenuto. Allora puoi ricreare una voce del menu principale senza il sotto-menu
.sub-menue cambiare la classe.titlein.title-link. Poi dai le stesse regole CSS che ha la classe.titleanche alla nuova classe.title-linke ovviamente metti il link che deve seguire nell’attributohrefdella nuova voce di menu principale.Spero di essere stato chiaro, se hai problemi fammi sapere.
Grazie mille, ce l’ho fatta.
ciao Main, eccomi di nuovo
Ho notato che il menu funziona bene su tutte le versioni di browser recenti: FF, safari, opera ecc. Mentre per l’amico IE funziona bene solo con la versione 8. Con IE6 e IE7 il menu funziona a scatti. Il movimento di chiusura e apertura della tendina non è fluido.
È possibile fare qualcosa?
grazie
Mi dispiace ma l’effetto dipende dalla libreria jQuery con plugin Easing. Prova ad aumentare la velocità dell’effetto e vedi se cambia qualcosa; al posto di
slowutilizza il parametrofast.Ciao bellissimo menu, ma avrei la necessità che ogni li sia diverso, mi spiego. Ora nella demo ci sono 4 categorie e tutte hanno il colore rosso. Io vorrei che fossero tutti 4 di colore diversi come posso fare?
Grazie
Caio a tutti, bel menù complimenti! Volevo però sostituire al colore rosso delle immagini, e per ogni link associarne una diversa, come posso fare?
Grazie
Scusate per il doppio post di prima, avrei un altra domanda. Quando posiziono il mouse sopra al link cè un effetto rollover che fa diventare il colore un rosso acceso. Vorrei che l’effetto rollover rimanesse anche aver aperto il sub menu
Ciao e complimenti per li super menu
veramente bello!
volevo farti una domanda però,
se io volessi fare in modo che al mio click su una voce del menu si aprisse un link e contemporaneamente si aprisse anche il sottomenu a fisarmonica? secondo te è fattibile?
grazie anticipatamente,
cordiali saluti
Ciao e anche da parte mia i complimenti per questo script.
)
Anche se lo leggo dopo svariato tempo lo sto provando solo adesso.
E volevo chiederti aiuto a proposito di:
come detto nei posto precedenti (ma non ci ho capito nada
sarebbe interessante avere i menu che rimango aperti una volta cliccato la voce e solo se si cambia categoria si chiude la precedente e si apre la nuovo.
Un po come fanno gli accordion…
2. prob.
come diceva trasher nell ultimo posto avrei anche io bisogno che le categorie siano linkabili ma che contemporaneamente i menù rimanessero aperti
Praticamente un insieme delle due cose richieste
Penso che se tu riuscissi ad aggiungere nel tuo tutorial anche queste due cose faresti bingo….
Grazie per la tua disponibilità
Ciao
Ciao
sto modificando il menù per integrarlo con asp e renderlo dinamico.
Nel menù faccio visualizzare le SuperCategorie nei titoli e le Categorie all’interno del sub-menu.
Il mio problema è che inserendo un ciclo dentro l’altro riesco a visualizzare le Categorie solo del primo pulsante e gli altri non mi si aprono! Qlc sa il xchè? Il codice è questo:
<a href="categoria_accordion.asp?id_super_categoria=”>
…
<a href="anag_gallery_dettaglio.asp?id_categoria=”>
scusate il codice che volevo visualizzare è questo:
<a href="categoria_accordion.asp?id_super_categoria=”>
…
<a href="anag_gallery_dettaglio.asp?id_categoria=”>
Ciao Pierhagi, forse il tuo codice non è completo prova a scriverlo tra tag <code> — codice — </code> oppure scrivi i caratteri speciali come entità HTML.
@ MaiNick:
Ciao e grazie di avermi risposto!
Ho provato ad inserire
ma non ho avuto esito positivo.Qlc mi ha suggerito di inserire nel un id per recuperare l’id_super_categoria dell’url perchè l’effetto parte sempre con la stessa funzione Javascript però bisogna dirgli a quale elemento far riferimento. Mettendo un’id che corrisponde poi all’id della categoria in modo che quando si clicca viene recuperato la querystring che contiene l’id e si dice a javascript esattamente qual’è l’elemento nel quale fare l’effetto.
Qlc sa spiegarmelo?
@Pierhagi scusami ma non ho capito bene il tuo problema. Nei messaggi precedenti ho compreso che hai un problema nel codice di visualizzazione dei sotto menu, mentre ora ho capito che tu vorresti aprire il sotto menu corrispondente alla pagina visitata; se quest’ultimo è il tuo bisogno puoi vedere l’ultimo articolo che ho pubblicato in cui c’è una versione aggiornata di questo tutorial modificato per risolvere tale problema.
Fammi sapere.
Ciao si c’erano degli errori di base nel codice che ti ho dato!
Per capirci descrivo cosa vorrei che facesse il menù.
Ad es. visualizzando la home del sito clicco su un pulsante, che x me sono le SuperCategorie, il menù si espande visualizzandomi le Categorie appartenti al pulsante cliccato rimanendo sempre nella pagina home!
Se clicco in una Categorie, cioè in una voce nel sub-menu mi deve visualizzare la pagina con la gallery di quella categoria!
Il mio problema è che queste azioni funzionano solo con il primo pulsante!
Se clicco su un pulsante qualsiasi che non sia il primo non ottengo lo stesso effetto xchè questi pulsanti non ricevono il valore id x poter visualizzare l’elenco delle categorie.
Credo che il codice js non faccia passare questi valori!
@Pierhagi scusami se ho capito bene vuoi che ci siano altri livelli di sotto menu SuperCategoria->Categoria->SottoCategoria. Allora bisogna modificare del tutto lo script.
Fammi sapere e se possibile puoi postarmi il link al tuo esempio per rendermi conto meglio di quello che vuoi fare.
Ciao no non voglio una sottocategoria, guarda qui:
http://www.fulminanti.it/categoria_accordion2.asp?id_super_categoria=29
se tu clicchi sul primo pulsante e cioè Abbigliamento ti si apre il menù con le categorie… e così è corretto!…ma se poi decidi di cliccare su un altro pulsante non si visualizzano più le categorie!
Ti dico già che il pulsante corretto è il “57 – Cappellini2″ xchè contiene il valore dell’id_super_categoria=57 che dovrà essere utilizzato per estrarre le categorie della supercategoria Cappellini.