Artiklen demonstrerer hvorledes du kan skabe et dynamisk dropdown menupanel eller en dropdown navigationsbjælke ud af en liste med indlejrede lister.
Mit udgangspunkt er en almindelig uordnet liste med indlejrede lister. (Eksempel 1). Denne liste er indsat på en side, der er layoutet med følgende stylesheet:
div#page { width:45em;position:relative; margin:1em auto; background:#efefff; padding:1em;} div#leftcol { width:12em; float:left;} div#rightcol { margin-left:12em;}
Det vil sige, jeg har en spalte med en bredde på 12 em til rådighed for mit menupanel. Som du kan se af eksemplet, er det ikke nok til at indeholde en uordnet liste med flere indlejrede lister.
Det kan vi imidlertid hurtigt ordne med noget stylesheet formatering af listerne:
div#leftcol ul { margin: 0; padding: 0; list-style:none; width: 11em; background: white; border-width: 1px 1px 0 1px; border-style: solid; border-color:#257;}
Resultatet af denne tilføjelse til vort stylesheet ser du i eksempel 2.
Bemærk i dette eksempel følgende:
list-style:none
fjerner listepunkt-markørerne (bullets) og sætter listepunktets tekst ud i venstre margin.Når alle ul
'erne formateres ens kommer de naturligvis til at
stå oven i hinanden.
Det laver jeg om på ved
li
'er en position:relative.
Så længe jeg ikke sætter nogen positionsangivelser,
bevarer li'erne
deres “naturlige” position. li
er nu en referenceramme
for den absolutte positionering af en ul
, der er indeholdt i en
li
:div#leftcol li { position: relative; list-style: none; margin: 0; padding:0; border-bottom: 1px solid #257;} div#leftcol ul ul { position: absolute; top: -1px; left: 11em;}
Bemærk her, at en ul
i en ul
har fået en
position left
på 11 em,
svarende til menuernes bredde. Det vil rykke alle indlejrede lister
til højre for deres forældrelement med 11 em.
Eksempel 3.
Nu står undermenuerne oven i hinanden, men det problem
forsvinder, når vi ændrer værdien for left
-positionen
i formdeklarationen. Ideen er jo, at alle
undermenuer skal være skjulte, indtil musen er over det menupunkt, der
har en undermenu:
div#leftcol ul ul {position: absolute; top: -1px; left: -1000em;}
I mine tidligere eksempler om dette emne har jeg brugt
display
-værdierne block
og none
til at ændre på visningen af undermennuerne: display:none
skjuler undermenuerne, mens display:block
viser undermenuerne.
Skærmlæsere og søgerobotter har imidlertid et ambivalent
forhold til blandt andet display
-værdierne. Derimod spiller
position ingen rolle og de fleste forfattere anbefaler nu anvendelsen af position
til dette formål. left:-1000em
flytter effektivt undermenuerne ud af browservinduet på
en visuel browser medmindre man har en skærmbredde på over 16.000 pixel...
Før vi kigger nærmere på, hvordan det ordnes således at undermenuerne vises, når musen er over menupunkterne, skal der pyntes lidt på menuerne.
div#leftcol li.sub { background-image:url(rarrow.gif); background-position:right center; background-repeat:no-repeat;} div#leftcol li a { display: block; padding: 0.25em 0 0.25em 0.5em; text-decoration: none; width:10.5em;} div#leftcol>ul a {width: auto;}
Jeg starter med at give alle de menupunkter, der har en undermenu,
en class="sub"
. Det gør det muligt for mig at
forsyne disse, og kun disse, med en lille pil tilhøjre,
der skal tilkendegive, at menupunktet skjuler en undermenu. Dernæst
formateres li
-markørernes indhold af links, med en
padding
, der giver alle menupunkter en vis fylde.
a
-elementet, der er et inline element,
skal have sin display
-egenskab ændret til block
.
Af hensyn til ældre versioner af Internet Explorer er vi nødt til at give a
-markøren en eksplicit bredde på 11 em
(10.5 em + 2 gange padding 0.25 em). Af hensyn til alle andre browsere
ophæver jeg denne i den sidste formregel i koden lige herover.
Nu er vi nået til eksempel 4.
Nu kommer to svære opgaver:
:hover
-effekt på listepunkterne, så menupunktet
skifter bagrundsfarve, når musen er over det, og display
-egenskaben for undermenuen fra
none
til block
.div#leftcol ul ul { position: absolute; top: -1px; left: 11em; display:none; } div#leftcol li:hover {background-color: #aaf;} div#leftcol ul.niveau1 li.sub:hover ul.niveau2, div#leftcol ul.niveau2 li.sub:hover ul.niveau3 { display:block;}
Ovenstående tilføjelser til stylesheet'et klarer sagerne. Bemærk
at den første formdeklaration er en gentagelse, hvor display
-egenskaben
for de indlejrede lister er ændret til none
, så de ikke vises.
Dernæst følger to konstekstuelle selektorer for mine undermenuer. Bemærk først at jeg har givet mine undermenuer et class name, niveau1 for topmenuen, niveau2 for undermenuer og niveau3 for undermenuer til undermenuer.
Nu skal den første kontekstuelle selektor læses således: Under en
given omstændighed skal en ul
, der har klassenavnet
niveau2, og som er barn af en li
med klassenavnet sub
og barnebarn af en ul
med klassenavnet niveau1
,
have display-egenskaben block
.
Den givne omstændighed er, at forældreelementet li.sub
er i :hover
tilstand. Og det er dette element når musen er over det.
Nu er vi nået til eksempel 5. Hvis du kun har Internet Explorer 6 som browser, behøver du ikke kigge på det eksempel. Den forventede funktionalitet glimrer ved sit fravær i denne browser. I enhver anden rimeligt moderne – inklusive Internet Explorer 7 og følgende – browser virker det fint.
Eksempel 6 virker derimod fint i alle moderne browsere, inklusive Internet Explorer 6. Hvordan jeg har opnået det forklarer jeg i det følgende afsnit.
Problemet med ældre versioner af Internet Explorer består i, at disse
browsere ikke kan fortolke pseudoklassen :hover
på andre elementer end
links. Og for ikke at gøre denne konstruktion unødigt kompliceret er
det afgørende, at vi kan benytte os af :hover
-effekten
på li
-elementer.
Den afgørende forskel på eksempel 5 og eksempel 6 er
følgende kodestump i head
-delen af eksempel 6:
<!--[if lt IE 7]> <style type="text/css" media="screen"> body {behavior: url(csshover.htc);} </style> <![endif]-->
Det, der sker her er, at jeg indsætter endnu et stylesheet for websiden. Jeg sørger for, at kun Internet Explorer indlæser dette stylesheet ved at bruge Microsofts betingede kommentar til at skjule HTML-kode for alle andre browsere end Microsofts egne. Derved undgår jeg at indlæse dette ekstra stylesheet i alle andre browsere. (Microsofts betingede kommentarer kan du læse noget mere om i min artikel om disse, Microsofts betingede kommentarer).
Inde i kommentarblokken finder du så det stylesheet, som kun
Internet Explorer benytter. Stylesheet'et indeholder kun én formdeklaration,
der knytter egenskaben behavior til body
-elementet.
Microsofts behaviors er DHTML-scripts, der tilfører HTML-elementer
dynamiske egenskaber ved hjælp af JavaScript eller Microsofts version
af JavaScript, JScript. Et sådant Javascript skal have filtypen .htc og
indlæses på siden ved hjælp af behavior
-egenskaben på den her viste måde.
Enhver kan konstruere sådanne behaviors, hvis man sætter sig ind i
hvordan de programmeres. Det ligger dog i yderkanten af mine evner.
Heldigvis har andre taget handsken op på netop det felt, jeg her
beskæftiger mig med, og som er:
Hvordan giver vi HTML-elementer de samme CSS-egenskaber i IE<7 som de
har i mere standardkompatible browsere.
Det mest udbredte af disse scripts er lavet af Peter Nederhof, og
kan downloades fra
whatever:hover
eller fra dette websted csshover.htc.
Dette script gør det muligt at benytte :hover
på et
vilkårligt HTML-element, når det knyttes til body
-elementet på
den måde, der er beskrevet ovenfor.
.htc-filen føjer ca. 3 kilobyte til den datamængde, der skal overføres for at vise siden. Det er derfor ikke afgørende, at du skjuler det ekstra stylesheet for andre browsere, som jeg har gjort i eksempel 6. Det kan uden videre tilføjes det almindelige stylesheet for skærmvisning, som jeg har gjort i eksempel 7. Browsere, der ikke kender behavior-egenskaben vil uden videre springe denne formdeklaration over.
Bemærk, at brugen af denne teknologi vil medføre, at dit stylesheet ikke kan validere som korrekt CSS af W3S's CSS-validator.
Bruger du Windows XP Professional og har servicepack 2 installeret, vil du muligvis opleve problemer med Internet Explorers indlæsning af .htc-filer.
I egenskaber for IIS skal du oprette eller ændre mime-type (under http-headers) til text/x-application. Jeg har indtil jeg oprindeligt skrev denne artikel brugt mime-typen text/Jscript, hvad voldte mig store problemer indtil jeg fandt ud af det.
Læs evt. mere hos Big John.
jfj, 22/9-2005
En menu skal jo på en eller anden måde integreres i en websides layout, hvadenten det drejer sig om et menupanel eller en navigationsbjælke eller måske begge dele.
Jeg er sluppet lidt billigt fra det, fordi layout'et på mine eksempelsider er temmelig minimalistisk:
div#page { width:45em; margin:1em auto; background:#efefff; border:1px solid #257;} div#leftcol { width:13em; float:left; padding-top:30px;} div#rightcol { margin-left:13em; border-left:1px solid #257; padding-left:1em;}
– plus foroven et sidehoved med et baggrundsbillede og en sidehovedtekst.
I min artikel Layout med float-egenskaben og denne artikels eksempler kan du læse en hel del om netop dette emne, så det vil jeg ikke gå i dybden med her.
Jeg har dog lavet yderligere et par kommenterede eksempler, der bygger på ovennævnte eksempel 7, hvor jeg viser, hvorledes du kan indpasse menupanelet i dels
Det er ret uproblematisk at gøre menuen højrestillet, jf. eksempel 8. Nøglen til denne løsning knytter sig til positioneringen af undermenuerne:
div#rightcol ul ul {position: absolute; top: -1px; right: 10em; display:none; }
Ganske som vi kan lave en "flad" navigationsbjælke med en vandretstillet liste, kan vi bruge de samme principper til at lave en navigationsbjælke med dropdown undermenuer.
Eksempel 9 viser navigationsbjælken.
Der findes andre .htc-filer, der der gør det samme, ligesom der findes
JavaScripts til indsætning i head
-delen af dokumentet, der
på forskellig vis tilfører en uordnet liste den samme funktionalitet som andre
browsere med hensyn til at få :hover
-pseudoklassen til at virke på li
-elementer.
De fleste af disse alternativer kræver dog, at du mingelerer mere med din HTML-kode og/eller din styleshet-kode end det synes strengt nødvendigt. Det er en af fordelene ved Nederhofs .htc-fil, at du kan bruge nøjagtigt den samme HTML-kode og nøjagtigt den samme CSS-kode som du ville bruge, hvis Internet Explorer < version 7 var lige så kompatibel med CSS-standarden som stort set alle andre nyere browsere.
Hvis og hvis og hvis... Hvis grise havde vinger ville de flyve.
I denne sag kan grise nu flyve. Der findes et JavaScript modulbibliotek (udviklet af Dean Edwards), der forandrer Internet Explorer fra en version 6 til en version 7, med de fleste af de forbedringer, Microsoft for længst burde have indført.
Eksempel 9a viser fuldstændig den samme webside som eksempel 9, men her er behavior-egenskaben fjernet og i stedet refererer siden til et eksternt JavaScript.
Det eksterne JavaScript, der er tale om, hedder i daglig tale IE 7, og kan findes i Googles kodebibliotek på webadressen http://code.google.com/p/ie7-js/. På websiden IE 7 demo kan du se hvilke selektorer og egenskaber, der efter indlæsning af dette modulbibliotek liplusli bliver tilgængelige også i Internet Explorer.
Når jeg selv skal bruge en sådan menu ‘for alvor”, vil jeg som regel gerne have den til at fylde det overordnede element helt ud, hvadenten det nu er body-elementet eller som her en CSS-boks, der rummer sidens indhold.
Eksempel 10 viser, hvorledes det tager sig ud.
Hvis det er absolut og meget meget nødvendigt kan det godt lade sig gøre at ordne det således, at menupunkterne lige præcis fylder menublokken ud, især i et tilfælde som dette, hvor bredden af menublokken er fikseret. Eksempel 11 viser én lettere sjusket måde at gøre det på.
Sandt at sige foretrækker jeg at bruge kulør for at skabe samling
på menublokken. Eksempel 12 viser,
hvorledes jeg har farvesat menuen, og brugt en baggrundsgrafik ved
:hover
-tilstanden.
Det kræver lidt større indgreb end de tidligere eksempler: Da vi
ikke kan have to baggrundsgrafikker på det samme element, og da vi
fortsat ønsker både en pil-ned og en baggrundsgrafik i hvert fald
ved :hover
-tilstanden, er jeg nødt til at knytte
baggrundsgrafik til både li
- og a
-elementerne.
I eksemplet har jeg fremhævet disse ændringer.
I eksempel 12 vil du bemærke, at jeg har sat nogle undermenupunkter ind under menupunktet yderst til højre. Du vil også hurtigt konstatere, at de undermenupunkter ikke er til megen nytte – de forsvinder, så snart jeg fører musen ned over dem.
Årsagen til forsvindingsnummeret er, at jeg på websiden har to lag,
der overlapper hinanden – dels det lag, det udgøres af menuen og
dens underpunkter, og dels det lag der udgøres af den højre kolonne
(#rightcol
-elementet).
Sådan som reglerne er for stakkeordenen af to (positionerede) lag der overlapper hinanden, vil #rightcol-elementet ligge øverst, fordi det er indlæst senere i kildekoden.
Heldigvis kan vi manipulere med denne stakkeorden ved hjælp af
z-index
-egenskaben. Så løsningen på problemet med den forsvindende undermenu er ganske enkelt at give menuen en højere z-index
-værdi end
#rightcol
-elementet. Dette element har ingen z-index-værdi, så enhver z-index-værdi for menuen større end 0 (Nul) vil ordne problemet, jf. eksempel 12a.
Det er i princippet ret ligetil at forsyne hvert menupunkt med en grafisk baggrund. Se for eksempel Grafisk rollover kun med CSS.
I eksempel 13har jeg taget skridtet videre og udført det sådan, at udsnit af sidehovedets billede vises som baggrund for hvert enkelt menupunkt. I :hover tilstande udskiftes hvert udsnit med et udsnit, hvor billedet er dæmpet.
Som jeg ser det, er der mange fordele ved denne meode at konstruere dynamiske menuer på: JavaScript-lamme browsere – og det så godt som alle browsere, der ikke er de visuelle browsere, vi bruger på vores laptops og desktop computere – viser menuen; er browseren desuden CSS-lam, vises hele menuen i udfoldet stand, hvad du let ser ved at indlæse en af mine eksempelsider og bruge dit eget, tomme stylesheet (jeg bruger jævnligt til IE et sådant stylesheet, som jeg har kaldt blank.css, og som ikke indeholder en eneste formdeklaration. I Firefox er det nemt, vælg No style i menuen Vis/Page Style).
Men der er også et par ulemper: For det første er det ikke muligt at indbygge nogen form for tidsforsinkelse i en sådan menu, som man jævnligt gør i en JavaScript DHTML menu. Tingene sker øjeblikkeligt, og det kan kræve en tilvænning hos brugere, der måske ikke er vant til at tingene sker så hurtigt.
Den mest skadevoldende effekt af denne hastige respons på brugerinput er, at en undermenu forsvinder øjeblikkeligt, hvis brugeren flytter musen blot en pixel uden for det aktive område. Det er faktisk derfor man ofte indbygger et par hundrede millisekunders forsinkelse i DHTML menuerne.
For nylig (september 2005) fandt jeg imidlertid hos Holly'n'John ( www.positioniseverything.net) et ganske probat middel til at bekæmpe denne uhensigtsmæssige virkning. Det går ganske vist ikke ud på at forsinke menuens reaktion, men det går ud på at sørge for, at musen skal virkelig langt uden for menuen, før den lukkes. ( http://www.positioniseverything.net/css-dropdowns.html.)
Oprettet: August 2005. Opdateret: April 2009