Webmenu

Hmm, (bijna) zonder Javascript! Versie 2.1!

Het menu bovenaan deze pagina’s lijkt heel gewoon. Maar achter de schermen is het best bijzonder: daar zit namelijk bijna niets!

Popup-menu’s op HTML-pagina’s zijn berucht vanwege de omvangrijke en ingewikkelde scripts die ze gebruiken. Soms gaat het om meer dan duizend regels onoverzichtelijke Javascript-code. Dat is zo omvangijk dat bugs vrijwel onvermijdelijk zijn. Zelfs websites die, naar we mogen aannemen, door professionals zijn ontworpen, kunnen daarvan last hebben. Er zijn er nogal wat waarbij Internet Explorer begint te klagen over een ‘runtime-fout’ (tenzij het foutzoeken in scripts door IE is uitgeschakeld, wat standaard het geval is). Soms is die zo erg dat het onmogelijk is om naar een andere pagina toe te navigeren.

De gangbare menuscripts zijn zo ingewikkeld omdat ze met alle browsers moeten werken, ook met oudere. Slimme en minder slimme functies moeten de eigenaardigheden van al die browsers compenseren.

De vraag is gewettigd of het middel niet erger is dan de kwaal. Van alle internetgebruikers heeft nog maar 0,15% Netscape 4.0, de belangrijkste oudere browser. Internet Explorer 4.0 staat op niet meer dan 0,05% van de pc’s. Kortom, ruim 99% van alle surfers gebruikt op zijn minst browsers van de 5.0-generatie. De meeste pc-bezitters zijn zelfs up to date: in oktober 2005 gebruikte 93% IE 6.0 of een op ‘Gecko’ gebaseerde browser zoals FireFox (Browser News).

Ziehier dan ook de moderne variant van het webmenu: eentje die in principe zonder Javascript werkt en helemaal is uitgevoerd met CSS-stijlregels. Zonder Javascript-ballast, voor browsers van nu en in de toekomst.

Doodgewone lijst

De ‘markup’ van het menu op deze pagina’s is een doodgewone ongeordende lijst (<ul>) van drie niveaus met links. Hij heeft als class "xmenu". De HTML ziet er ongeveer zo uit:

<ul class="xmenu">
    <li><a href="index.html">Home</a>
        <ul>
            <li><a href="wie.html">Sjaak wie?</a>
            <li><a href="priesters.html">Meer Priesters</a>
        </ul>
    ...
    <li><a href="computers.html">Computers</a>
        <ul>
            <li><a href="web.html">Webtrucs</a>
                <ul>
                    <li><a href="webmenu.html">Webmenu</a>
                    <li><a href="fotoshow.html">Fotoshow</a>
                    ...
                </ul>
            <li><a href="codeguru.html">CodeGuru</a>
            ...
        </ul>
    ...
</ul>

Dat is al een heel verschil met de krankzinnig ingewikkelde arrays waarmee Javascript-menu’s moeten worden geïnitialiseerd.

De crux zit hem in de volgende CSS-stijlregels:

.xmenu {
    margin: 0;
    padding: 0;
    list-style-type: none }
.xmenu li {
    margin: 0;
    padding: 0;
    position: relative;
    float: left }
.xmenu ul {
    margin: 0;
    padding: 0;
    visibility: hidden;
    position: absolute }
.xmenu ul li {
    float: none }
.xmenu li:hover ul {
    visibility: visible }

Alle padding’s en margin’s van de <ul> en de list-items <li> worden op 0 gezet en de list-style op none, zodat voorlooppunten worden onderdrukt.

De <li> van het topniveau krijgt float: left mee, waardoor de keuzemogelijkheden niet onder elkaar komen te staan, maar naast elkaar. Dat wordt voor de <li> van het tweede niveau weer ongedaan gemaakt met float: none. (Hetzelfde effect kan worden bereikt met display: inline en display: block.)

De <ul> van het tweede niveau krijgt een absolute positionering. Dat betekent dat hij als het ware uit de ‘float’ van normale elementen wordt gelicht, geen ruimte op de pagina inneemt, en bovenop de normale elementen wordt gelegd. Bovendien wordt hij met visibility: hidden onzichtbaar gemaakt.

De laatste stijlregel maakt de <ul> van het tweede niveau zichtbaar als met de muis boven de <li> wordt gehoverd. Omdat de <lu> van het tweede niveau een childnode is van de <li> van het eerste niveau, blijft hij zichtbaar zolang de muis erboven hangt.

Dat is alles!

Was dat maar waar...

De HTML-markup en de vijf stijlregels werken vlekkeloos onder de beste browsers die er zijn, Firefox, Mozilla en de andere van ‘Gecko’ afgeleide zoals Netscape. Ook het dappere product van de Noorse software-industrie, Opera, dat met een marktaandeel van 0,45% stand houdt tegen de grote jongens, kan er aardig mee uit de voeten.

Roet in het eten

Zoals gewoonlijk is het weer eens Microsoft Internet Explorer dat roet in het eten gooit. IE 6.0 ondersteunt namelijk de ‘pseudo class’ :hover (nota bene een uitvinding van Microsoft zelf) alleen op CSS1-niveau, en nog niet op CSS2-niveau. Gelukkig zijn er behaviors om ons uit de brand te helpen. Kijk op mijn IE hover-pagina voor uitleg.

Met een slimme behavior zou het Internet Explorer ook moeten werken. Zou, want er is nog meer nodig om Microsoft’s schepping bij de les te houden. IE heeft nog veel meer kuren. Zo positioneert IE bijvoorbeeld de <lu> niet goed ten opzichte van de <li> op een hoger niveau. Moeten een aantal onderdelen een expliciete breedte hebben. Werkt het alleen als sommige elementen een achtergrondkleur hebben. Enzovoort, enzovoort.

Gepeuter

Al met al is er nog heel wat gepeuter aan de stijlregels nodig voordat we een menu hebben dat behoorlijk werkt onder IE, Mozilla, Opera, en in principe onder alle andere browsers die zich aan de standaard van de W3C-organisatie houden.

In de tweede versie van het menu zijn ook stijlregels toegevoegd om het tot drie niveaus te laten werken. Er zit ook een verticale variant in: ken de markup de class .ymenu toe in plaats van .xmenu en er is een ietwat experimentele verticale variant (die helaas totaal niet werkt in Opera):

In de meest recente versie is een kleine, maar subtiele wijziging aangebracht na een suggestie van Yves Horsmans.

In browsers die zich niet aan de W3C-standaard houden, komt alleen het bovenste niveau in beeld. Hetzelfde geldt voor IE waarbij Javascript is uitgeschakeld. Er is dus sprake van wat in computerjargon ‘graceful degradation’ wordt genoemd: het ziet er ook nog acceptabel uit als niet alles meewerkt. Een voorwaarde is wel dat de pagina’s op het topniveau buiten het menu nog een andere manier bieden om naar de onderliggende pagina’s door te linken; anders worden die voor gebruikers van IE met uitgeschakeld Javascript onbereikbaar.

In browsers die helemaal geen CSS ondersteunen, of waarvan de gebruiker een andere style sheet heeft ingeschakeld, verschijnt een nette lijst met normale links. Ook speciale browsers, zoals de voorlezers die slechtzienden gebruiken, presenteren het menu op een behoorlijke manier — wat je van sommige Javascript-gedrochten niet kunt zeggen.

Oude browsers kunnen totaal niet overweg met het menu. En dan bedoel ik ook echt totaal niet. In IE 5.0 zie je, althans met de horizontale variant, balken als een waanzinnige over het scherm op en neer springen. De website wordt volkomen ontoegankelijk. Ik had het liever anders gezien, maar ga er ook niet om zitten kniezen. In IE 5.5 werkt het in principe goed, maar mooi ziet het er niet uit.

Wie er ook mee aan de slag wil, kan in het volgende kleine (942 bytes) zip-bestandje de stijlregels (in "xymenu.css") en het bijbehorende behavior (in "hover.htc") aantreffen.

Download xymenu

Gebruiksaanwijzing

  1. zet de links in een ongeordende lijst (<ul>) van maximaal drie niveaus;
  2. geef de <ul> de class="xmenu" voor de horizontale variant, en class="ymenu" voor de verticale;
  3. zorg dat de CSS-regels uit het bestand "xymenu.css" geladen zijn en pas ze naar smaak aan door regels toe te voegen;
  4. zorg dat het bestandje "hover.htc" beschikbaar is in de map van de pagina (dus niet alleen in de map van "xymenu.css".

Aanpassen stijlregels

Doe dat door nieuwe regels te maken die na die van "xymenu.css" komen en dus de oorspronkelijke overschrijven.

Gebruik de volgende richtlijnen voor de horizontale variant:

  • Geef .xmenu ul een width. Op deze site gebruik ik 8.5em.
  • Moeten de blokjes op het topniveau even breed zijn?
    • ja - geef width van .xmenu a de gewenste breedte;
    • nee - laat de width oningevuld.
  • Moeten de blokjes een andere hoogte dan de regelhoogte hebben?
    • ja - pas de padding van .xmenu a aan;
      of: geef height van .xmenu a de gewenste hoogte (kan alleen als ook width een vaste waarde heeft).
  • Moet er ruimte tussen de blokjes op het topniveau?
    • ja - geef margin-right van .xmenu li de gewenste ruimte.
  • Moet er verticale ruimte tussen de blokjes op het subniveau?
    • ja - geef margin-top van .xmenu a de gewenste afstand.
  • Pas eventueel de background-color van .xmenu ul aan. Er moet een background-color zijn; transparent werkt niet in IE.

Richtlijnen voor de verticale variant:

  • Geef .ymenu en .ymenu ul een width.
  • Moeten de blokjes een andere hoogte dan de regelhoogte hebben?
    • ja - pas de padding van .ymenu a aan;
      of: geef height van .ymenu a de gewenste hoogte (kan alleen als ook width een vaste waarde heeft).
  • Moet er verticale ruimte tussen de blokjes?
    • ja - geef margin-top van .ymenu a de gewenste afstand.
  • Pas eventueel de background-color van .ymenu ul aan. Er moet een background-color zijn; transparent werkt niet in IE.

Richtlijnen voor beide varianten:

  • Zorg dat de submenu’s niet over een form, een object of een applet komen; ze komen er niet overheen (geen enkel menu krijgt dat voor elkaar, trouwens).
  • Zet de document mode op HTML 4 Strict of XHTML, anders maakt IE de blokjes smaller dan de andere browsers.

Het is mogelijk om individuele keuzeblokjes een afwijkende kleur of achtergrondafbeelding te geven. Doe dat als volgt:

  1. Geef de <li> van de betreffende keuze een id, zeg "speciaal".
  2. Definieer stijlregels voor #speciaal a en/of #speciaal a:hover met daarin afwijkende color, background-color, background-image en/of border-color.