In questo articolo vedremo come creare un menu centrato a più livelli attraverso una marcatura XHTML 1.0 valida in puro CSS. A tal fine abbiamo preso come esempio uno dei numerosi menu disponibili su cssplay.co.uk, modifcandolo in base alle nostre esigenze. Ecco la demo.
Come si può notare dalla demo proposta, tutto il menu è stato inserito in un blocco div con classe '.centeredmenu' in modo da poter creare stili specifici a partire dalla classe stessa e in modo tale da non interferire con lo stile restante della nostra pagina.
Inoltre il codice XHTML è praticamente identico a quello dei noti menu proposti da Stuart Nicholls,
ma differisce per la sola presenza di tag inline <ins>, che racchiudono sia la lista <ul>
in ciascuno dei sottomenu, sia il menu stesso:
...
<li><a href="#">Voce 2
<!--[if gte IE 7]><!--></a><!--<![endif]-->.
<!--[if lte IE 6]><table><tr><td><![endif]--><ins><ul>
<li><a href="#">sottovoce 2_1</a></li>
<li><a href="#">sottovoce 2_2</a></li>
<li><a href="#">sottovoce 2_3</a></li>
</ul></ins>
<!--[if lte IE 6]></td></tr></table></a><![endif]-->
</li>
...
...
<div class="centeredmenu">
<ins><ul>
...
</div>
...
Il motivo per cui sono stato inseriti questo elementi inline aggiuntivi sarà chiaro durante la spiegazione del codice. Creiamo innanzitutto il codice XHTML necessario, con alcune definizioni base di stile, ma privo
di qualsiasi tipo di formattazione specifica al menu (ecco il primo step).
Inseriamo quindi lo stile necessario per visualizzare il primo livello del nostro menu. La regola:
.centeredmenu {
width : 860px;
font-size : 1.2em;
margin : 0 auto;
}
stabilisce che l'area orizzontale del nostro menu sarà larga al massimo 860px, mentre con la regola successiva eliminiamo ogni possibile stile alle nostre liste <ul>.
La regola:
.centeredmenu ins {
display : block;
text-align : center;
...
position : relative;
z-index : 1;
width : 100%;
}
rappresenta il nostro contenitore all'interno del quale centreremo la lista <ul>. Si noti che un elemento con display: block
dovrebbe estendersi in orizzontale tanto quanto è lo spazio a sua disposizione, ma dello stesso avviso non è Safari 3 per Windows, per cui forziamo tale comportamento dichiarando width: 100%
.
Com'è noto per centrare un oggetto (il nostro <ul>) all'interno di un contenitore (l'elemento <ins>) si attribuisce di norma al primo una larghezza e margin: ... auto;
(mentre al secondo bisogna specificare text-align: center
per la compatibilità
su Internet Explorer). Tuttavia non possiamo procedere in questo modo, altrimenti saremo costretti a specificare una larghezza
per ogni lista annidata e ciò rappresenterebbe un grosso limite (ad esempio in caso di menu dinamici generati da CMS, o in presenza di
font che non occupano lo stesso spazio in differenti piattaforme).
Per aggirare tale problema dichiariamo display: table
alle liste <ul> e display: table-cell
agli elementi di lista <li>. Così facendo le nostre liste annidate si comporteranno come tabelle, le cui celle saranno rappresentate dai list-item. Il text-align: center
applicato all'<ins> avrà come effetto quello di centrare la lista annidata (secondo step).
Si noti infine l'uso del selettore '>' che applicato in questo modo
...
.centeredmenu ins li:hover > ins {
display : block;
position : absolute;
z-index : 10;
left : 0;
top : 1.8em;
}
...
ci garantisce che - all'hover su una voce di lista - solo il sottomenu successivo sarà aperto e non tutti i sottomenu seguenti.
Funzionamento su Internet Explorer
Se si visualizza il secondo step avremo già ottenuto un menu che funziona perfettamente su tutti i browser, ad eccezione di Internet Explorer. Ci sono infatti alcune modifiche da effettuare per realizzare lo stesso effetto su questo browser e a tal fine
utilizzeremo i commenti condizionali.
Innanzitutto è bene ricordare che, su Explorer, parte del codice XHTML del menu è anch'esso generato in base ai commenti condizionali: sarà quindi necessario eliminare lo stile di default dell'elemento <table> e <td>:
...
.centeredmenu table {
border-collapse : collapse;
border : 0;
margin : 0;
padding : 0;
}
...
Modifichiamo anche lo stile dell'elemento <ins>:
...
.centeredmenu ins {
width : 860px;
background-image: url(transparent-1x1.gif);
}
...
Si noti che su quest'ultima regola abbiamo dovuto specificare una larghezza in pixel (quella precedente, definita in valore percentuale, non ha effetto, sebbene sia stato dichiarato in precedenza display: block;
) pari a quella massima
del nostro contenitore del menu; inoltre abbiamo specificato un'immagine di sfondo (trasparente, 1px per 1px ripetuta)
per evitare un fastidioso bug a causa del quale
il menu sembra essere 'bucato' (si provi la demo definitiva su IE6 e 7 eliminando questa specifica proprietà) e incapace
di mantenere aperto il sottolivello all'hover.
Ora è necessario modificare la proprietà display degli elementi <ul> e <li>. Infatti le dichiarazioni display: table
e
display: table-cell
non sono purtroppo supportate sui browser di casa Redmond precedenti alla versione 8, come
illustrato in questa tavola di compatibilità,
quindi definiamo le seguenti regole alternative:
...
.centeredmenu ul {
display : inline-block;
}
.centeredmenu ul {
display : inline;
margin : 0 auto;
}
.centeredmenu li {
float : left;
display : inline;
}
...
Fortunatamente IE6 e IE7 supportano (anche se in modo incompleto e buggato) la proprietà inline-block,
attraverso la quale si possono definire degli elementi blocco tali da estendersi in orizzontale quanto basta per racchiudere
il contenuto. Tuttavia per definire un elemento inline-block su IE è necessario ripetere due volte la stessa regola: nella
prima va definito display :
, mentre nella seconda dichiariamo inline-block;
display : inline
;.
Gli elementi <li> sono invece floattati (con display: inline;
per evitare il double margin bug).
Un workaround per il child-selector su IE6
Inseriamo infine queste regole solo per Explorer 6 e precedenti che non supportano il selettore figlio '>'
<!--[if lte IE 6]>
<style type="text/css">
.centeredmenu a:hover ins { display : block; }
.centeredmenu a:hover ins ins { display : none; }
.centeredmenu a:hover ins a:hover ins { display : block; }
.centeredmenu a:hover ins a:hover ins ins { display : none; }
.centeredmenu a:hover ins a:hover ins a:hover ins { display : block; }
.centeredmenu a:hover ins a:hover ins a:hover ins ins { display : none; }
</style>
<![endif]-->
ottenendo la demo finale.
In generale si dovranno ripetere tante coppie di regole quanti sono i sottolivelli del nostro menu.
Ciascuna coppia sarà scritta nella forma:
.centeredmenu (a:hover ins){1,n} { display : block;}
.centeredmenu (a:hover ins){1,n} ins { display : none; }
dove 'n' è appunto il numero di submenu (3, nel caso della demo).
Considerazioni finali
Il menu è stato testato con successo con IE6/7, Firefox 2.0.0.16/3.0.1, Opera 9.50 e Safari 3.1.2 per Windows; con Firefox 3 su Ubuntu 8.04; con Safari 3.0.4 e Firefox 2.0.0.15 su MacOs X 10.4.11.
Il codice CSS è stato realizzato in modo tale da poter essere integrato in maniera modulare (tramite commenti condizionali) in modo da poter essere facilmente modificato e/o integrato a seconda della versione di IE che si vuole supportare (o dismettere).
Abbiamo visto inoltre come utilizzare la proprietà 'display' in modo da poternesfruttare 5 differenti valori ('block', 'inline', 'inline-table', 'table' e table-cell').
Con un po' di immaginazione è possibile utilizzare questa demo per creare una specie di puzzle o un gioco di abilità legato al movimento del mouse nel quale bisogna trovare un percorso per arrivare all'ultimo livello del menu. O ancora, per generare dei disegni che appaiono mano a mano che vengono scoperti i sottolivelli.
Tutto il materiale proposto è disponibile per il download.