Drop down menu.

Bron: http://www.sceneone.nl/tips_tricks/drop_down_menu.php

Titel: HTML en CSS tutorials

Auteur: Wybe Weysters

Het drop down menu is een veelgebruikte manier om een uitgebreide navigatie te structureren.
Je kunt op een overzichtelijke manier je navigatie groeperen en iedere bezoeker van je website begrijpt meteen hoe het werkt en wat de bedoeling is.
Er is een enorme hoeveelheid informatie over te vinden. In Google krijg ik 104 miljoen resultaten op 'drop down menu', inclusief een aantal betaalde zoekresultaten zoals 'DHTML Menu Generator' of 'Drop Down Menu Builder'.

DHTML

Zoals je gewend bent van mijn tutorials gaan wij de code met de hand schrijven. Dus 'Create professional cross-browser drop down menus within minutes!' gaat voor ons niet op.
Daar staat tegenover dat (als het goed is) jij dadelijk wél begrijpt wat je gedaan hebt en hoe het een en ander werkt.
Ik wil nog terugkomen op de hierboven genoemde 'DHTML Menu Generator' en vooral op dat DHTML. Dat is namelijk wat wij ook gaan maken, een DHTML menu.
Het DHTML gedeelte is eigenlijk heel eenvoudig te omschrijven. DHTML is de samenwerking tussen html, css en javascript. De samenwerking tussen deze drie heeft altijd een zekere interactiviteit tot gevolg en dat is natuurlijk ook de bedoeling. In ons geval is dat het uitklappen van een submenu wat hoort bij een hoofdmenu item. Dat uitklappen gebeurt op het moment dat de bezoeker met de cursor over een hoofdmenu item heen gaat.

Aan de slag

Zoals je weet bestaat dé manier om een navigatie te structureren uit de ul. Je kunt eigenlijk wel zeggen dat een beetje navigatie in een ul thuishoort. Mocht het zo zijn dat dit nieuw voor je is, dan is het misschien wat om eerst het hoofdstuk over navigatie eens door te nemen.
We gaan dus maar eens beginnen met het opzetten van de hoofdnavigatie in een list met daarin de subnavigatie in geneste lists:

CSS: GEEN HTML: <ul>

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat

Als je niet precies begrijpt wat hierboven gebeurd met die geneste ul enzo moet je dit maar eens bekijken.

De volgende stap bestaat uit het aanbrengen van een basis structuur en het verwijderen van een aantal zaken zoals bullits, margins en paddings.
Omdat ik een horizontale hoofdnavigatie wil zal de basis structuur ook daaruit bestaan.
Here we go:

CSS: #nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}

#nav li {
float: left;
width: 120px;
}

#nav ul {
position: absolute;
width: 120px;
}
HTML: <ul id="nav">

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat

Even een korte uitleg over hoe, wat, waar.
In de eerste declaratie (#nav, #nav ul) worden alle margins en paddings op 0 gezet en de list style op none (weg met die bullits). Ik heb in de html de eerste ul de id 'nav' gegeven en die spreek ik vanuit m'n css aan. Daarnaast maak ik gebruik van het feit dat de geneste ul een child is van de ul met de id 'nav'. Op die manier pak ik in één declaratie alle ul's.

In de tweede declaratie (#nav li) target ik alle li's die een child zijn van 'nav'. Ik laat ze links floaten waardoor de hoofdnavigatie op 1 lijn komt te staan. Ditzelfde zou gebeuren met de subnavigatie (de geneste li's zijn immers ook children van 'nav') ware het niet dat alle li's een breedte hebben gekregen van 9em.
De li van de hoofdnavigatie is 120px breed. De geneste li's van de subnavigatie zitten als het ware gevangen in die li van de hoofdnavigatie. En die geneste li's zijn dus ook 120px breed. Er is voor die geneste li's dus geen ruimte om naast elkaar te gaan staan, ook al zouden ze dat wel willen. Ze worden onder elkaar gedwongen.

Als laatste geef ik de geneste ul nog een absolute positionering, zodat ik deze dadelijk makkelijk kan manipuleren. En nog een keer die 120px breed om de boel goed dicht te timmeren.

Volgende stap

Ik wil nu af van die subnavigatie. Die mag niet zichtbaar zijn. Pas als een bezoeker met z'n cursor over een van de hoofdnavigatie items gaat mag die subnavigatie zichtbaar worden.
Dat gaan we doen met een vuiligheidje. We gaan die subnavigatie een negatief linker coördinaat geven waarmee we zeker weten dat daarmee die hele subnavigatie van de pagina verdwijnt.....grijns. Bijvoorbeeld -1000px:

CSS: #nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}

#nav li {
float: left;
width: 120px;
}

#nav ul {
position: absolute;
width: 120px;
left: -1000px;
}
HTML: <ul id="nav">

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat

Zo daar zijn we vanaf. Nu willen we natuurlijk wel dat die subnavigatie terugkomt 'on hover'.
We doen eerst even (zoals wel vaker) alsof het leven van een webdesigner over rozen gaat. Met andere woorden, we doen even alsof Internet Explorer niet bestaat. Toe maar, doe maar even mee. Even heerlijk wegdromen. In een wereld zonder IE kunnen we zonder problemen de eigenschap 'hover' aan andere elementen koppelen dan alleen aan de 'a'. Bijvoorbeeld aan een li.
Je krijgt dan in je stylesheet dit: li:hover. No problemo. En dat gaan we doen:

CSS: #nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}

#nav li {
float: left;
width: 120px;
}

#nav ul {
position: absolute;
width: 120px;
left: -1000px;
}

#nav li:hover ul {
left: auto;
}
HTML: <ul id="nav">

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat (in Firefox)

Wat we met die laatste declaratie eigenlijk zeggen is: voor iedere ul die een child is binnen het element met de id 'nav' en tegelijkertijd een child is van een li waarvoor geldt dat de bezoeker er met z'n cursor overheen gaat geldt dat hij zijn linker coördinaat zelf moet bepalen. Met andere woorden zijn linker coördinaat moet zijn wat het was vóór de declaratie -1000px en daarmee springt dus de subnavigatie die hoort bij het hoofdnavigatie item waar je met je cursor overheen gaat terug in de pagina...............ben je er nog.
Je kunt ook gewoon denken, het zal me een worst wezen. Het werkt en daar gaat het om.

Ondertussen, in de werkelijke wereld.........

......was er ook nog Internet Explorer. Shit da's waar ook. En IE snapt dat verhaal met die 'hover' gekoppeld aan die li niet. Dus dat moeten we anders doen, namelijk met javascript. Ik ga hier niet teveel uitwijden over de ins en outs van het gebruikte javascript. Wat ik je wel wil meegeven is dat je met javascript ook gebruik kunt maken van het parent-child verhaal en dat je met javascript ook een bepaalde id van een html element kunt aanspreken. Zoals je dat met css ook kunt. En dat doet dit javascript ook.
Als je het javascript bekijkt kom je de id 'nav' tegen, dus let op! Als je die id 'nav' in je html verandert moet je dat in het javascript ook aanpassen anders gaat het fout.
Ik voeg het volgende javascript toe aan de head van de pagina waarin ik mijn menu heb zitten:

JavaScript: <script language="JavaScript">
sfHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" ie_does_hover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" ie_does_hover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);
</script>

In het javascript is op een aantal sprake van 'ie_does_hover'. Dit slaat op een class die we in de stylesheet moeten aanmaken:

CSS: #nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}

#nav li {
float: left;
width: 120px;
}

#nav ul {
position: absolute;
width: 120px;
left: -1000px;
}

#nav li:hover ul, #nav li.ie_does_hover ul {
left: auto;
background-position: 0 0;
}

#nav a {
display: block;
}
HTML: <ul id="nav">

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat (in Firefox en Internet Explorer)

Nou, dat was 'm wel zo'n beetje. Nog wat opmaken misschien:

CSS: #nav, #nav ul {
padding: 3px 0 0 0;
margin: 0;
list-style: none;
}

#nav li {
float: left;
width: 120px;
}

#nav ul {
position: absolute;
width: 120px;
left: -1000px;
}

#nav li:hover ul, #nav li.ie_does_hover ul {
left: auto;
background-position: 0 0;
}

#nav a {
display: block;
margin: 2px 5px 3px 5px;
text-decoration: none;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 1em;
}

ul a{
font-weight: bold;
color: #F60;
cursor: default;
}

ul ul a:link, ul ul a:visited{
font-weight: normal;
color: #CCC;
cursor: pointer;
}

ul ul a:hover, ul ul a:active{
font-weight: normal;
color: #FFF;
cursor: pointer;
}

ul li{
background-color: #CCC;
border-left: 3px solid #FFF;
}

ul ul li{
background-color: #666;
border-top: 3px solid #FFF;
border-left: 0;
}

/* IE only hack \*/
* html ul li, * html ul ul li{
border-bottom: 3px solid #FFF;
}

* html ul ul li{
border-top: 0;
}
/* Einde IE only hack */
HTML: <ul id="nav">

<li><a href="#">Main item 1</a>

<ul>
<li><a href="#">Sub item 1.1</a></li>
<li><a href="#">Sub item 1.2</a></li>
<li><a href="#">Sub item 1.3</a></li>
<li><a href="#">Sub item 1.4</a></li>
</ul>

</li>

<li><a href="#">Main item 2</a>

<ul>
<li><a href="#">Sub item 2.1</a></li>
<li><a href="#">Sub item 2.2</a></li>
<li><a href="#">Sub item 2.3</a></li>
<li><a href="#">Sub item 2.4</a></li>
<li><a href="#">Sub item 2.5</a></li>
</ul>

</li>

<li><a href="#">Main item 3</a>

<ul>
<li><a href="#">Sub item 3.1</a></li>
<li><a href="#">Sub item 3.2</a></li>
</ul>

</li>

</ul>

bekijk het resultaat

De css die ik in het laatste voorbeeld heb toegevoegd lijkt heel wat, maar het gaat alleen om opmaak.
Het enige wat nog noemenswaardig is, is de Internet Explorer hack die ik op het laatst gebruik. Dit doe ik alleen om een klein verschil tussen IE en Firefox ongedaan te maken.

Verder zou ik zeggen, probeer zelf eens wat met bovenstaande code. Dan merk je vanzelf wat wat is en hoe het werkt. Gewoon uit elkaar trekken en opnieuw in elkaar zetten.

Tot slot nog even dit. Je kunt dit menu nog verder uitbreiden met een subsub-menu en als je wilt zelfs een subsubsub-menu. Als je wilt weten hoe dat werkt moet je bij htmldog zijn.

Succes en plezier ermee!

naar het begin van de pagina