Menu a tendina orizzontale


Stanchi dei soliti menu a tendina verticali di cui dispone "di default" l'HTML? Beh, stavo cercando un modo alternativo di mostrare dei contenuti di un menu e avevo in testa l'organizzazione della pagina principale della sezione "Webdesign", cosi' ho unito le due cose, aggiunto un pizzico di idee personali sull'apertura del menu, ho mescolato bene e il codice e' venuto fuori quasi da sé...
Per capire meglio come funziona il menu completo, ho diviso la sua creazione in due fasi: l'espansione/riduzione del menu e l'apparizione/sparizione del suo contenuto.

La prima fase consiste nel creare una tabella con 2 celle: la prima conterrà il futuro bottone che apre e chiude il menu e la seconda cella sarà il campo di testo dove appariranno le voci del menu.

Qui sotto c'è l'esempio della prima fase, ovvero un menu vuoto con un pulsante "Prova" che serve per espandere/contrarre il menu:

P
r
o
v
a



Ed ecco il codice per creare l'animazione del menu:

<table border="1">
<tr>
<td rowspan="2" width="30">
<center>
<div style="border:3px outset green;background:green" onclick="intv_esp= setInterval('espandi()',1);quale=uno;i=0;" onmousedown="this.style.border='3px inset green'" onmouseup="this.style.border='3px outset green'" onmouseover="this.style.cursor='hand'" onmouseout="this.style.cursor='default';this.style.border='3px outset green'"> P<br>r<br>o<br>v<br>a </div>
</center>
</td>
<td style="visibility:hidden" id="uno">
&nbsp;
</td>
</tr>
</table>

<script language="javascript">

var i=0;
var m=300;
var intv_esp;
var quale;
var direz=false;

function espandi()
{
/////////////Gestione espansione
if(direz==false)
{
if(i<301)
{
quale.style.width=i;
i+=5;
}
if(i>300)
{
clearInterval(intv_esp);
direz=true;
return;
}
}
///////////////

//////////////Gestione ritiro
if(direz==true)
{
if(m>0)
{
quale.style.width=m;
m-=5;
}
if(m<=0)
{
clearInterval(intv_esp);
direz=false;
m=300;
return;
}
}
/////////////
}

</script>

La prima parte del codice crea una tabella. Non viene specificata la larghezza delle celle per due motivi: la prima contiene un <div> con una parola scritta in verticale (semplicemente vado a capo con <br> dopo ogni lettera), quindi molto sottile, e la seconda deve non avere misura perché deve essere "mobile". Se infatti guardate la seconda cella noterete che contiene soltanto un carattere di spazio forzato &nbsp per rendere visibile la cornice della cella stessa.
Quello che ci interessa di più è il tag <div>. Esso è infatti il bottone vero e proprio. Ha un bordo di 3px verde in rilievo e lo sfondo verde; quando si fa click su di esso creiamo una variabile e la associamo ad un intervallo di 1 millisec per la funzione espandi(). L'intervallo deve essere assegnato ad una variabile perché altrimenti non sarebbe possibile disattivare tale intervallo una volta raggiunta la dimensione massima di espansione (qui sono 300 pixel). La variabile quale serve per indicare la cella da espandere (nel caso sia abbia più di un menu) e poi la var i viene portata a zero.
Gli onmousedown, onmouseup, onmouseover e onmouseout servono rispettivamente per creare l'effetto bottone premuto, cambiando stile del bordo quando il mouse viene premuto/rilasciato, per cambiare il cursore con quello a forma di mano quando si passa sopra il bottone e per ripristinare il cursore di default quando siamo fuori dal bottone.

Lo script crea cinque variabili e una funzione.
Le variabili sono in ordine:
  • i: inizializzata a zero, viene usata per impostare la larghezza del menu in espansione;
  • m: inizializzata a 300 (dimensione max del menu), viene usata per impostare la larghezza del menu in compressione;
  • intv_esp: usata da onclick per impostare un intervallo entro il quale richiamare la funzione;
  • quale: argomento di onclick per stabilire quale cella deve essere espansa/contratta (così siamo già pronti ad usare più menu di questo tipo insieme);
  • direz: variabile booleana per stabilire se al click sul bottone il menu deve espandersi o contrarsi. In questo modo non devono essere usate funzioni differenti per i due movimenti del menu.

La funzione espandi() si divide in due parti tramite il controllo sul valore di direz. Se è false allora bisogna espandere in menu. Fino a che non si è raggiunta la larghezza stabilita (300 px) si assegna il valore i alla larghezza e si incrementa tale variabile di 5. Raggiunta la dimensione desiderata (i maggiore della dimensione massima stabilita) si rimuove l'intervallo, si inverte direz e si mette un return per uscire.
Se al click direz è true allora il menu va fatto contrarre con del codice uguale ma "inverso" a quello per espanderlo.


Così com'è però il menu non è che serva a tanto, visto che non mostra niente...
Adesso facciamo un po' di teoria su quello che deve accadere nello script per porter visualizzare correttamente il contenuto del menu.

Per prima cosa, tale contenuto... non va visualizzato! O per lo meno non va visualizzato fino a che il menu non sia completamente espanso. Questo perché altrimenti la tabella assumerebbe come dimensioni minime quelle per farci entrare il contenuto dei menu. E a noi non va bene.
Allora per comodità lasciamo come contenuto della seconda cella uno spazio forzato (&nbsp) fino a che il menu non è completamente espanso, quindi impostiamo il contenuto della cella e successivamente lo rendiamo visibile. Per fare questo occorre una funzione di setup del teso, che in base al valore della variabile "quale" imposta una stringa creata in precedenza (per comodità e per non dover rendere il codice troppo oscuro). Quando poi si clicca nuovamente per chiudere il menu bisogna fare la cosa inversa, ovvero rendere invisibile il testo, sostituirlo con uno spazio forzato e far tornare indietro il menu.

<table border="1">
<tr>
<td rowspan="2" width="30">
<center>
<div style="border:3px outset green;background:green" onclick="intv_esp= setInterval('espandi()',1);quale=uno;i=0;" onmousedown="this.style.border='3px inset green'" onmouseup="this.style.border='3px outset green'" onmouseover="this.style.cursor='hand'" onmouseout="this.style.cursor='default';this.style.border='3px outset green'"> <br>P<br>r<br>o<br>v<br>a<br><br>
</div>
</center>
</td>
<td style="visibility:hidden" id="uno">
&nbsp;
</td>
</tr>
</table>

<script language="javascript">

var i=0;
var m=300;
var intv_esp;
var quale;
var direz=false;

function espandi()
{
/////////////Gestione espansione
if(direz==false)
{
if(i<301)
{
quale.style.width=i;
i+=5;
}
if(i>300)
{
clearInterval(intv_esp);
direz=true;
setup_testo(quale);
return;
}
}
///////////////

//////////////Gestione ritiro
if(direz==true)
{

clear_text(quale);

if(m>0)
{
quale.style.width=m;
m-=5;
}
if(m<=0)
{
clearInterval(intv_esp);
direz=false;
m=300;
return;
}
}
/////////////
}


var uno_txt = "Primo elemento\<br\>\<a href\=\"http:\/\/web.tiscali.it\/alexmfm\" target\=\"_blank\"\>Link secondo elemento\<\/a\>\<br\>\<br\>\<div style\=\"border:3px outset green\"\>Terzo oggetto\<\/div\>\<br\>";

function setup_testo(id_menu)
{
if(id_menu==uno)
{
id_menu.innerHTML=uno_txt;
id_menu.style.visibility="visible";
}
}

function clear_text(id_menu)
{
if(id_menu==uno)
{
id_menu.style.visibility="hidden";
id_menu.innerHTML="";
}
}

</script>

Vediamo soltanto i cambiamenti apportati al codice precedente:
ci sono tre tag <br> nel testo prova del "bottone", giusto per rendere l'area del bottone più alta, dato che altrimenti quando appaiono le voci del menu, il tasto si sposta.

Nella funzione espandi(), quando tutto il menu è espanso (ovvero nel caso i>300) viene richiamata la funzione setup_testo() che imposta il contenuto della cella con la stringa inizializzata più sotto con il testo appropriato e successivamente lo rende visibile.
Quando invece si fa click per chiudere il menu, il testo viene prima reso invisibile e poi "tolto" dal menu, impostando come testo interno al menu una stringa vuota grazie al metodo clear_text().

Nota: tutti quei backslash nella stringa di testo servono per scongiurare che il browser interpreti i segni di uguale, maggiore o minore o apici in modo non corretto. Anche se l'unico problema reale dovrebbe essere con gli apici, dato che il javascript non è "schizzinoso", qualche backslash in più non crea problemi.


Il risultato finale è questo (attenzione: se vi viene voglia di sbirciare il codice noterete che i nomi di variabili e metodi sono leggermente differenti, ma è dovuto al fatto che avendo già messo lo script per il menu vuoto, me ne serve un altro simile che faccia più o meno la stessa cosa senza incasinare le variabili già usate):


P
r
o
v
a



L'unico bug che ho riscontrato non solo in questo script, ma in tutti quelli che usano degli intervalli è che quando se ne usano più di uno, inevitabilmente le animazioni vanno più veloci! Più intervalli sono presenti e più le singole animazioni vanno veloci. L'unico modo di rimediare è fare delle prove e impostare un intervallo maggiore per ogni variabile interessata.

E adesso fantasia, fantasia e fantasia per utilizzare questi menu nella maniera che ritenete più opportuna per le vostre pagine!!!