Het originele artikel over de Suckerfish Dropdowns op A List Apart bewees dat het een populaire manier was om lichtgewicht en toegankelijke CSS dropdown-menu's te maken waarbij Internet Explorer een handje werd geholpen door de :hover pseudo-class na te apen.
Suckerfish is terug. De techniek is toegankelijker, afgeslankt (slechts 12 regels Javascript), werkt beter in diverse browsers (het werkt nu ook in Opera en Safari zonder maar een spoor van een hack) en er kunnen meerdere submenu's gebruikt worden.
Okee. Laten we er maar niet omheen draaien. De HTML code waar we in eerste instantie mee gaan werken is de volgende:
<ul id="nav">
<li><a href="#">Percoidei</a>
<ul>
<li><a href="#">Remoras</a></li>
<li><a href="#">Tilefishes</a></li>
<li><a href="#">Bluefishes</a></li>
<li><a href="#">Tigerfishes</a></li>
</ul>
</li>
<li><a href="#">Anabantoidei</a>
<ul>
<li><a href="#">Climbing perches</a></li>
<li><a href="#">Labyrinthfishes</a></li>
<li><a href="#">Kissing gouramis</a></li>
<li><a href="#">Pike-heads</a></li>
<li><a href="#">Giant gouramis</a></li>
</ul>
</li>
<!-- etc. -->
</ul>We hebben wat basisopmaak nodig om fatsoenlijk te kunnen werken:
#nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}
#nav a {
display: block;
width: 10em;
}
#nav li {
float: left;
width: 10em;
}#nav li, omdat Opera er anders een rommeltje van maakt. Omdat we elementen aan het floaten zijn, moeten we de content onder de dropdowns clearen (clear:left).
Logischerwijs moeten we de lijsten waarvan we willen dat ze 'down droppen' onzichtbaar maken, maar om alles zo toegankelijk mogelijk te maken moeten we display:none; vermijden, want dit maakt ook dingen onzichtbaar voor sommige screen readers, zoals vele malen vermeld is in artikelen over het vervangen van afbeeldingen. Je denkt misschien dat er tal van manieren zijn om dit op te lossen, maar na uitvoerig geëxperimenteerd te hebben met breedtes, hoogtes, marges, top-waardes en 'clipping' in een aantal browsers zijn we er achter gekomen dat de beste oplossing (Dit is sowieso handig voor het herbergen van meerlaagse lijsten) het gebruiken van left is.
De CSS specificaties vertellen ons dat top, right, bottom en left waardes een absoluut gepositioneerde box moet verplaatsen ten opzichte van de box waar hij in zit. Helaas heeft Opera besloten absoluut gepositioneerde boxen te verplaatsen ten opzichte van de pagina en daarom werkte het originele Suckerfish menu ook niet in Opera. Deze vertrouwden op de top en left eigenschappen met expliciete waardes.
In plaats van display:none; gebruiken we dus left:-999em; om de dropdown menu's weg te werken en later gebruiken we left:auto; (dit liever dan left:0;) om ze weer terug te krijgen.
#nav li ul {
position: absolute;
width: 10em;
left: -999em;
}
#nav li:hover ul {
left: auto;
}En hiermee zijn we klaar wat betreft de browsers die de :hover pseudo-class volledig ondersteunen, maar voor Internet Explorer moeten we de Suckerfish Javascript in actie laten komen:
sfHover = function() {
var sfEls = document.getElementById("nav").getElementsByTagName("LI");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=" sfhover";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);Feitelijk erkent dit de 'sfhover' class aan <li> elementen in <ul>s met id="nav" wanneer de muis er op komt en verwijdert de class ook weer met een reguliere expressie als de muis van het element af gaat.
Nu gooit Suckerfish er dus een nieuwe class uit. De volgende stap is het simpelweg kopieëren van de eigenschappen bij de :hover selector naar de sfhover selector:
#nav li:hover ul, #nav li.sfhover ul {
left: auto;
}Alsjeblieft. Hier heb je je standaard enkellaags dropdown menu.
Het originele artikel over Suckerfish dropdowns ging alleen over enkellaags dropdown menu's. Met slechts een kleine uitbreiding van de trapsgewijze logica is het goed mogelijk ook meerlaagse dropdowns met CSS te maken. In tegenstelling tot de originele Suckerfish Javascript code kent de 'sfhover' functie nu de class toe aan alle <li> elementen in 'nav'dan alleen aan de directe children elementen, dus meerlaagse dropdowns zijn nu ook gewoon mogelijk in Internet Explorer.
Om te beginnen nemen we de volgende opbouw van meerdere lijsten:
<ul id="nav">
<li><a href="#">Percoidei</a>
<ul>
<li><a href="#">Remoras</a>
<ul>
<li><a href="#">Echeneis</a></li>
<li><a href="#">Phtheirichthys</a></li>
<li><a href="#">Remora</a></li>
<li><a href="#">Remorina</a></li>
<li><a href="#">Rhombochirus</a></li>
</ul>
</li>
<li><a href="#">Tilefishes</a></li>
<li><a href="#">Bluefishes</a></li>
<li><a href="#">Tigerfishes</a></li>
</ul>
</li>
<li><a href="#">Anabantoidei</a>
<!-- etc. -->
</li>
<!-- etc. -->
</ul>Er zijn een paar dingen die we moeten toevoegen aan de enkellaagse manier. Als eerste moet de derde laag (in dit voorbeeld 'Echeneis, 'Phtheirichthys' enz.) tevoorschijn komen naast het lijst elementen waar het in staat (in dit geval is dat 'Remoras'). Hiervoor gebruiken we de volgende regel, die van toepassing is op alle lagen na de eerste:
#nav li ul ul {
margin: -1em 0 0 10em;
}Omdat we de top van de absoluut gepositioneerde boxen niet expliciet kunnen opgeven zitten ze onder de regel van het lijst element waar de muis op staat. Daarom moet de bovenmarge van de volgende laag ingesteld worden op -1em. Nu komen de menu's hoger te staan, maar nog niet hoog genoeg, omdat de regelhoogtes standaard groter dan 1em zijn (meestal 1.2em). We moeten dus een klein beetje code toevoegen aan de originele regels voor de <ul>s:
#nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
line-height: 1;
}Door het trapsgewijze (Cascading) effect waardoor de tweede laag weergegeven wordt komt de derde laag ook tevoorschijn. We moeten die derde laag nog wel expliciet verbergen (onthoud dat de code voor de :hover pseudo-class ook van toepassing moet zijn op de sfhover class):
#nav li:hover ul ul, #nav li.sfhover ul ul {
left: -999em;
}Nu kan deze regel omgedraaid worden zodat de het menu tevoorschijn springt zodra het lijst element door de muis aangewezen door simpelweg de regel om de dopdown te laten zien uit te breiden (voor de enkellaagse dropdown was het #nav li:hover ul, #nav li.sfhover ul { left: auto; }):
#nav li:hover ul, #nav li li:hover ul, #nav li.sfhover ul, #nav li li.sfhover ul {
left: auto;
}Hiermee krijgen we een stevig dubbellaags dropdown menu.
Als we met dezelfde logica verder gaan, dan kan je zoveel lagen menu's maken als je zelf wilt:
Voor drie lagen menu's:
#nav li:hover ul ul, #nav li:hover ul ul ul, #nav li.sfhover ul ul, #nav li.sfhover ul ul ul {
left: -999em;
}
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li.sfhover ul, #nav li li.sfhover ul, #nav li li li.sfhover ul {
left: auto;
}En in de ondenkbare situatie van vier lagen:
#nav li:hover ul ul, #nav li:hover ul ul ul, #nav li:hover ul ul ul ul, #nav li.sfhover ul ul, #nav li.sfhover ul ul ul, #nav li.sfhover ul ul ul ul {
left: -999em;
}
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li li li li:hover ul, #nav li.sfhover ul, #nav li li.sfhover ul, #nav li li li.sfhover ul, #nav li li li li.sfhover ul {
left: auto;
}Misschien heb je al gekeken naar de voorbeelden met één laag, twee lagen en drie lagen, waar je waarschijnlijk het beste naar de kale code in werking kan kijken. Natuurlijk kan je de zaak er mooier uit laten zien. Je kan er zelfs een verticaal menu van maken in plaats van een horizontale.