(aggiornamento riguardante solo i menù a tendina che si espandono verso l’alto: vedi qui)

Avevo già scritto qualcosa sui menù a tendina, arrivando a consigliare di utilizzare SuperFish, che a tutt’ora considero un ottimo plugin. Vediamo però come realizzare da zero un menù a tendina completo, utilizzando solo e semplicemente Jquery e limitandoci (per questo articolo, più in là semmai approfondirò) a un solo livello di profondità (in altri termini: i sotto-menù, a loro volta, non si espanderanno).

Due piccole premesse:

  1. dovete conoscere bene html e css, in quanto qui ci limiteremo (per questi due) allo stretto indispensabile;
  2. qui utilizzeremo un menù principale orizzontale (quindi le voci del menù affiancate) con sotto-menù in verticale (quindi voci elencate). Nulla toglie che poi, in base alle proprie esigenze e con le giuste modifiche, si possa operare diversamente (esempio: entrambi verticali).

Innanzitutto è necessario e doveroso scrivere del codice html pulito e conforme. Potete tenere a riferimento le considerazioni già espresse nel precedente articolo, e quindi scrivere un codice di questo genere:

<ul>
	<li><a href="pagina1.html">Pagina 1</a></li>
	<li>
            <a href="#">Pagina 2</a>
            <ul>
               <li><a href="paginaA.html">Pagina A</a></li>
               <li><a href="paginaB.html">Pagina B</a></li>
               <li><a href="paginaC.html">Pagina C</a></li>
            </ul>
        </li>
	<li><a href="pagina3.html">Pagina 3</a></li>
</ul>

È fondamentale notare come sia corretto organizzare il sotto-menù: il tag <ul> del sotto-menù (riga 5) è all’interno del tag <li> (riga 3) da cui si estende, che include anche il tag <a> (riga 4) che funge da finto-collegamento (in questo caso, perché deve essere funzionale solo all’estensione del sotto-menù) e da testo di riferimento per il sotto-menù. Potete vedere un primo esempio (solo html) qui.

Passiamo al foglio di stile. Innanzitutto aggiungiamo un id al menù principale (nell’esempio sarà navbar e quindi <ul id=”navbar”>), così da facilitarne la selezione (sia nel foglio di stile, sia con Jquery; e ricordo che in entrambi bisogna anteporre il cancelletto (#) davanti al nome), poi aggiungiamo delle proprietà css di base affinché il menù diventi così. Non le riporto per intero in questo articolo, potete trovare il foglio di stile qui.

Alcuni commenti:

  1. si seleziona il menù principale con #navbar (avendo l’<ul> principale id navbar, come già detto), i sotto-menù con #navbar ul (non solo quelli di primo livello, semmai ce ne fossero di inferiori!), entrambi (menù principale e sotto-menù) unendo le due con una virgola (quindi: #navbar, #navbar ul su un’unica riga);
  2. il menù principale si estende orizzontalmente, i sotto-menù (anche qui, non solo quelli di primo livello, ma tutti) verticalmente. Ciò significa che che una regola generale potrebbe (e spesso ha bisogno di) essere riscritta o perfezionata per essere applicata a uno stesso elemento contenuto in un sotto-menù di livello inferiore (il punto 4 di questo elenco ne è un esempio);
  3. dare una posizione assoluta ai sotto-menù (riga 13) è utile affinché siano indipendenti per quanto riguarda le misure (che saranno automatiche e calcolate in base al contenuto). Per eventuali altri sotto-livelli, ho notato dei problemi (sempre con le misure) credo imputabili ai limiti di Css 2. In questi casi, è bene specificare delle larghezze minime assolute per i sotto-menù, che potrebbe comunque essere – a prescindere – una buona pratica, anche per motivi estetici;
  4. i <li> del menù principale devono essere “flottanti” a sinistra per essere mostrati uno affianco all’altro (riga 23), visto che di default un elenco (<ul>) si estende in verticale. Questa regola viene annullata per i <li> dei sotto-menù (riga 30), visto che l’ordinamento di default va bene (anche i sotto-menù si estendono in verticale);
  5. bisogna annullare lo stile dei menù (riga 24);
  6. le <a> hanno bisogno della proprietà display impostata a block (riga 36), altrimenti non avranno le stesse dimensioni dei <li> che le contengono;
  7. le modifiche di stile al passaggio del mouse (righe 45-47) vengono “attivate” al passaggio del mouse su un <li> (infatti troviamo li:hover), ma vengono applicate alla <a> contenuta in quel <li>, visto che è alla <a> che viene definito un stile (righe 34-40). Le modifiche vengono applicate solo alla <a> “primo figlio” (meglio in inglese: first child) tramite il > (riga 45), per evitare comportamenti non voluti (se togliete il > e passate sul <li> che contiene un sotto-menù, noterete che le modifiche vengono applicate anche a tutte le <a> del sotto-menù e non solo a quella che apre il sotto-menù – è normale, visto che anche quelle sono “figlie” del <li> principale, proprio per la struttura html che abbiamo (correttamente) definito).

In questo esempio – come sicuramente avrete già notato – il sotto-menù è mostrato sempre, diremmo “fisso”: ho scelto così per permettere di visualizzare nel complesso l’applicazione del foglio di stile. Normalmente, però, non dovrebbe essere così, quindi dobbiamo nasconderlo. Per farlo utilizzeremo la proprietà display settata su none, da applicare a tutti i sotto-menù. Quindi, a questo punto, dobbiamo aggiungere sotto la riga 12 quanto segue:

display: none;

Notare che si potrebbe usare anche la regola visibility (settata su hidden), che porta allo stesso risultato ed è anche migliore da un punto di vista strettamente semantico; ma dobbiamo necessariamente ricorrere a display, perché Jquery lavora su questa proprietà per modificare la visibilità di un elemento.
Fatto questo, l’esempio aggiornato è questo e il relativo foglio di stile questo qui.

Non resta che aggiungere Jquery. L’operazione da eseguire è: al passaggio del mouse su un <li>, mostra l’<ul> first child (anche qui, altrimenti se usiamo più livelli di sotto-menù, li estenderebbe subito tutti). Va da sé che se un <li> non ha nessun <ul> figlio, non accade nulla. Quindi innanzitutto includiamo Jquery (all’interno dei tag <head>):

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
	$(document).ready(function(){
	 	//Il nostro codice andrà qui...
	});
</script>

Per attivare un effetto al passaggio del mouse su un <li>, possiamo usare l’evento hover() (documentazione). Il nostro codice diventa quindi (ometto l’inclusione del .js di Jquery e i vari tag <script>):

$(document).ready(function(){
	$("#navbar li").hover(function (){
		//L'effetto da applicare va qui...
	});
});

Che semplicemente corrisponde a: al passaggio del mouse (evento hover()) su un (qualsiasi) <li> contenuto nell’<ul> #navbar (quindi #navbar li), applica la funzione alla riga 3 (che qui dobbiamo implementare).

Di effetti disponibili ce ne sono parecchi (lista completa): noi utilizzeremo slideToggle() (documentazione), ma si valutino anche il classico toggle() (documentazione) e fadeToggle() (documentazione), che differiscono per lo più per il tipo di animazione (si fa prima a provare che a descrivere in questo articolo). Il codice diventa quindi:

$(document).ready(function(){
	$("#navbar li").hover(function (){
		$(this).children("ul").slideToggle();
	});
});

Che sta a significare: applica l’effetto slideToggle() al figlio <ul> (grazie a children() (documentazione)) dell’attuale <li> (this) su cui si è passato il mouse. Ecco quindi il nuovo esempio (il foglio di stile è sempre lo stesso, non lo abbiamo toccato), che soddisfa le necessità iniziali.

Manca giusto una (ultima) cosa, per lo più un “orpello”: come fare a capire (ad occhio, per il visitatore) quali menù contengono un sotto-menù. È diffusa l’abitudine di aggiungere il carattere “»” (ascii &#187;) ai menù che contengono un sotto-menù, pratica chiara e immediata. Potremmo occuparci di questa “aggiunta” manualmente, ma perché farlo (e faticare e rischiare di commettere errori o di non aggiornare in là col tempo), quando Jquery può occuparsi anche di questo e al posto nostro?
D’altronde la cosa è semplice: ciclare tutti i <li> del menù (<li> a qualsiasi profondità, ovviamente), verificare se hanno un <ul> figlio (con un costrutto if) e in caso positivo aggiungere il carattere (preceduto da uno spazio!) alla fine del link.

Bene, passiamo al codice. Per ciclare possiamo utilizzare each() (documentazione):

$("#navbar li").each(function() {
	//Fa qualcosa ad ogni <li> all'interno di #navbar...
});

che, in questo caso, eseguire la funzione qui dichiarata su ogni elemento <li> all’interno di #navbar. Quindi la verifica, per la quale possiamo affidarci a length (documentazione):

$("#navbar li").each(function() {
	if ($(this).children("ul").length) //Fa qualcosa ad ogni <li> all'interno di #navbar che contiene un <ul>...
});

In sostanza, in questo esempio lenght è pari al numero degli <ul> figli del <li> per il quale stiamo eseguendo il ciclo (sempre il famoso selettore this), e quindi l’if avrà esito negativo se non ci sono <ul> figli, viceversa positivi se c’è almeno un <ul> figlio – nota: questo if può essere generalmente utilizzato per verificare se un tag ne contiene un altro ed eventualmente in quale quantità.
Quindi l’aggiunta:

$("#navbar li").each(function() {
	//Se un <li> contiene un sotto-menù, aggiunge al collegamento " »"
	if ($(this).children("ul").length) $(this).children("a").append(" &#187;");
});

Utilizziamo il manipolatore append() (documentazione) per aggiungere uno spazio e un carattere alla <a> figlia di ogni <li> che ha come figlio un <ul> – sembra un ragionamento contorto, sì, lo so; ma riflettete un po’ sul codice e ci arriverete: l’aggiunta va fatta alla <a> contenuta nel <li> e non al <li> sul quale abbiamo eseguito il controllo.

Ecco quindi il codice Jquery finale e completo:

$(document).ready(function(){
	$("#navbar li").hover(function (){
		$(this).children("ul").slideToggle();
	});
	$("#navbar li").each(function() {
		//Se un <li> contiene un sotto-menù, aggiunge al collegamento " »"
		if ($(this).children("ul").length) $(this).children("a").append(" &#187;");
	});
});

Nonché, l’ultimo esempio.

Espandi/comprimi Commenti
mattia
(23/02/2012, 10:11)

sei un grande, propio quello che cercavo!!!

Paolo Modugno
(28/03/2012, 16:38)

Ciao Mirko, ho seguito alla lettera il tuo tutorial… nel mio caso mi servirebbe un menu con una tendina che si aprisse verso l’alto e non verso il basso… sapresti darmi qualche suggerimento su come fare? ti ringrazio!

[…]  (26) settembre 2010  (19) agosto 2010  (12) Ultimi 10 commentiPaolo Modugno su Tutorial Jquery: menù a tendinamattia su Tutorial Jquery: menù a tendinaTouch su Debian: i mirror più velocikbusta su Debian: i […]

XHTML - Puoi usare questi tag: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>