Einzelnen Beitrag anzeigen
  #2 (permalink)  
Alt 14.06.2006, 17:55
Benutzerbild von heiko_rs
heiko_rs heiko_rs ist offline
Erfahrener Benutzer
XHTMLforum-Kenner
 
Registriert seit: 18.09.2005
Ort: Berlin
Beiträge: 9.848
heiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblickheiko_rs ist ein wunderbarer Anblick
Standard

Erstellung von Menüs - und welche Extra-Regeln der Internet Explorer < 8 dafür benötigt
(am 24.07.2010 um weitere Abschnitte ergänzt)


Vorab einige Anmerkungen: Sämtliche hier erklärten Methoden und Techniken habe ich erfolgreich getestet im IE-Win ab 5.0 (der IE-Mac bleibt außenvor), Opera ab 7.0, Gecko (z.B. Firefox und Netscape) ab Netscape 7.0, sowie Safari ab 3.0 (ältere Versionen habe ich nicht getestet, dürften aber ebenfalls keine Probleme bereiten). Auch der IE 8 stellt erfreulicherweise alles auf Anhieb korrekt dar, also werden Hacks nur für die IE-Versionen 7 und kleiner benötigt. Voraussetzung dafür ist natürlich ein Doctype, der die IE-Versionen 6 bis 8 im Standardsmode rendern lässt.

Und obwohl die meisten der nachfolgend beschriebenen Bugs den IE < 7 betreffen, kann zeitweilig auch der IE 7 betroffen sein (und sei es auch nur ansatzweise). In diesen Fällen helfen die für den IE 6 beschriebenen Methoden auch für den IE 7 einwandfrei. Allerdings muss berücksichtigt werden, dass "hasLayout" (deutsche Übersetzung) beim IE 7 nicht durch das für den IE < 7 beschriebene height: 1px; ausgelöst werden darf, sondern auf eine der anderen in dem verlinkten Artikel beschriebenen Weisen.

10) Vertikale Menüs

Um dieses Markup

Code:
<ul id="navi">
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
als vertikales Menü mit über die volle Menü-Breite anklickbaren Links darzustellen, reicht nach einer "Grundeinstellung" (zur ersten Regel bitte auch "CSS-Prolog" in mazzos Posting beachten) in Form von

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	list-style: none;
	width: 15em;
	}
strenggenommen bereits folgende CSS-Regel:

Code:
#navi a {
	display: block;
	}
Höhe der Links sowie Einrückung und vertikale Ausrichtung der Linktexte werden durch padding erzeugt.

Oft sieht man zwar auch eine Vertikalzentrierung per line-height, jedoch ist davon abzuraten, da diese Methode erstens sehr ungenau ist, zweitens bei Zeilenumbruch überdimensionierte Zeilenabstände bewirkt, und drittens Text mit großer line-height extrem sensibel auf Textzoom reagiert, d.h. er wandert bei Vergrößerung wesentlich schneller nach unten als bei geringer line-height, so dass die Vertikalzentrierung sehr schnell verlorengeht.

Vor allem aus letzterem Grunde sollte für die Vertikalzentrierung von Menü-Texten immer eine geringe line-height gewählt werden, erst recht wenn der Text in einem Menü mit fester Höhe vertikal zentriert werden soll (wovon grundsätzlich allerdings abzuraten ist). In diesem Falle wird die Vertikalzentrierung des Textes erzielt, indem a height und padding-top bekommt (padding-bottom sollte hierbei Null sein). Dank geringer line-height wird sich der Text bei Vergrößerung nur unwesentlich nach unten bewegen, so dass das Menü relativ viele Vergrößerungsstufen verträgt, bevor sein Text überläuft.

Da Links nicht auf sich selber zeigen sollten, bietet sich an, auf der jeweils betrachteten Seite den entsprechenden Menülink zu entfernen und durch z.B. <strong> oder <em> zu ersetzen, nach dem Prinzip <li><strong>Home</strong></li>, und dieses Element grundsätzlich genauso zu stylen wie <a>, nach folgendem Prinzip:

Code:
#navi a,
#navi strong {
	display: block;
	padding: 0.5em;
	}
(Abweichende Formatierungen für <strong>, z.B. Farben oder font-weight, werden gesondert deklariert.)

Das sollte übrigens immer gemacht werden, auch bei allen nachfolgend erklärten IE-Hacks: Alle Maßnahmen für <a> müssen immer auch auf <strong> angewandt werden (auch wenn ich es nicht jedesmal explizit schreibe).

Alle Browser stellen das Menü damit gleichermaßen dar, mit Ausnahme des IE < 7 für Windows, dessen Darstellung in folgenden Punkten abweicht:

1. Die Links sind nicht über die volle Breite anklickbar (sondern nur ihr Text)
2. Der IE < 7 erzeugt unerwünschte Abstände zwischen den Links (verursacht durch den "Whitespace-Bug", der durch die Zeilenumbrüche im Quelltext ausgelöst wird)

Für den IE 6 wird beides behoben, indem die Links hasLayout bekommen, beispielsweise durch eine Dimension in Form von width oder height. Da es allerdings meist umständlich (und ohnehin überflüssig) ist, eine Breite für die Links zu definieren (zumal dies unter Umständen auch eine Boxmodell-Korrektur für den IE 5.x erfordert), kann man den Links auch durch eine Minimalhöhe hasLayout geben. Dies geschieht beim IE < 7 durch height: 1px; (da diese Versionen height wie min-height interpretieren).

IE 5.5 und 5.0 stellen das Menü allerdings immer noch nicht einwandfrei dar: Beide rücken die Links etwas nach rechts (genau an die Position, die sie bei der Darstellung mit Listenpunkt einnähmen). Dies geschieht übrigens auch im IE 6, falls #navi floatet und wegen des "Doubled-Float-Margin-Bugs" display: inline; bekommt. Darüberhinaus zeigt der IE 5.0 immer noch kleine Lücken zwischen den Links. Abhilfe für alle Punkte schafft:

Code:
#navi li {
	display: inline;
	}
(Die Links stehen durch ihr display: block; weiterhin untereinander.)

In manchen Fällen kann es allerdings wichtig sein, dass #navi li z.B. margin- oder padding-Deklarationen bekommt, die es als Inline-Element natürlich nicht mehr uneingeschränkt annimmt. In diesen Fällen kann eine Alternative zu display: inline; angewandt werden:

Code:
#navi li {
	width: 15em;
	float: left;
	clear: left;
	}
clear: left; kann strenggenommen entfallen, da eine horizontale Anordnung von <li> durch die definierte Breite ihres Elternelementes <ul> verhindert wird. Außerdem kann - sofern <li> keine seitlichen border-, padding- oder margin-Werte bekommt - als Alternative zu width: 15em; auch der Wert 100% genommen werden (denn dann muss z.B. bei einer späteren Änderung der Breite von <ul> die Breite von <li> im IE-CSS nicht angepasst werden).

11) Einbindung der Extra-Regeln für den IE

Alle oben genannten Extra-Regeln dürfen nur vom IE < 7 gelesen werden; dies wird am Besten durch einen Conditional Comment (CC) innerhalb von <head> erreicht (der CC steht hinter - d.h. unter - der Einbindung des Standard-Stylesheets):

Code:
<!--[if lt IE 8]>
<link rel="stylesheet" type="text/css" href="ie.css" />
<![endif]-->
(Ggf. sollte noch das media-Attribut ergänzt werden.)

Das so eingebundene Stylesheet "ie.css" wird ausschließlich vom IE gelesen, in den Versionen von 5.0 bis 7, während der IE 8 außenvor bleibt ("lt IE 8" bedeutet "less than IE 8"), da dieser - wie eingangs bereits erwähnt - für alle hier erklärten Techniken keinerlei Hacks benötigt. Weiterhin bleiben auch der IE 4 (und kleiner) sowie der IE-Mac (alle Versionen) außenvor, denn diese Browser kennen keine CCs.

Ich empfehle übrigens, nicht jede IE-Version mit einem eigenen CC anzusprechen, sondern ausschließlich den genannten CC zu verwenden und die verschiedenen IE-Versionen darin mit den üblichen Hacks anzusprechen, um nicht am Ende drei oder noch mehr CCs innerhalb von <head> zu haben.

Im konkreten Fall enthält das IE-Stylesheet folgende Regeln:

Code:
* html #navi li {
	display: inline;
	}

* html #navi a,
* html #navi strong {
	height: 1px;
	}
Und damit wird das Menü sogar vom IE 5.0 genauso dargestellt wie im neuesten Firefox oder Opera.

12) Horizontale Menüs

Es gibt zwei Möglichkeiten für die horizontale Darstellung:

1. #navi li bekommt display: inline; (die Links dürfen dann nicht als Block dargestellt werden)
2. #navi li bekommt float: left;

12.1) Die inline-Variante

Bei dieser Variante wird in der Regel #navi a margin und padding zugewiesen, damit sich die anklickbare Link-Fläche vergrößert und die Links ggf. einen kleinen Abstand zueinander haben:

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	list-style: none;
	text-align: center;
	}

#navi li {
	display: inline;
	}

#navi a,
#navi strong {
	margin: 0 1em;
	padding: 0.5em;
	}
(list-style: none; kann strenggenommen entfallen, da die Listenpunkte bereits durch display: inline; für <li> verschwinden. Anmerkung dazu: Das Element <li> hat den display-Initialwert "list-item".)

Der IE 7 zeigt bei dieser Variante einen Bug beim Zoomen der Seite: Die seitlichen Abstände der Links verschwinden, so dass sie unmittelbar nebeneinander stehen. Abhilfe schafft zoom: 1; für #navi a. Falls sowohl #navi als auch #navi a vertikales padding haben, müssen die Werte von #navi nun angepasst (d.h. etwas verringert) werden, denn im IE werden inline-Elemente durch zoom prinzipiell zu inline-block-Elementen, und werden dadurch von ihrem Elternelement auch anders behandelt. Es schadet übrigens nicht (und ist in manchen Fällen sogar sinnvoll), diese Änderungen auch allen älteren IE-Versionen zu zeigen.

Man muss zwar beachten, dass die Eigenschaft "zoom" Microsoft-proprietär und daher nicht valide ist, aber da das entsprechende CSS dem IE per CC zugewiesen wird (siehe oben), kann man darüber hinwegsehen - der CSS-Validator tut dies schließlich auch

Der IE 5.0 kennt die Eigenschaft zoom nicht, lässt sich aber durch height: 1px; zu einem identischen Verhalten bewegen. Und genau diese Deklaration ist im konkreten Fall auch für #navi a nötig, denn fehlt sie, akzeptiert der IE 5.0 (im Gegensatz zu allen späteren Versionen) weder margin noch padding für die Links, so dass das Menü dort quasi in sich zusammenfällt.

Nutzt man für sein horizontales Menü die Variante per display: inline; für #navi li, stellt man fest, dass (selbst bei Reduzierung jeglicher margins auf Null) immer ein kleiner horizontaler Abstand zwischen den einzelnen Links bleibt. Dieser entsteht durch den Quelltext-Whitespace (Leerzeichen bzw. Zeilenumbrüche im HTML-Quelltext) zwischen den einzelnen li-Elementen. Was auf den ersten Blick verwundern mag, ist ein normales und völlig logisches Verhalten: Inline-Elemente werden hier ähnlich wie Fließtext behandelt, und bei diesem möchte man ja auch, dass ein Quelltext-Leerzeichen zwischen 2 Wörtern einen kleinen horizontalen Abstand zwischen ihnen bewirkt.

Eine mögliche Abhilfe wäre, jeglichen Whitespace zwischen den li-Elementen auszukommentieren oder ihn zu entfernen, indem man alle <li> in einer Zeile direkt aneinander schreibt, aber diese Methode hat den Nachteil, dass dadurch kein Umbruch mehr entsteht, wenn die Links z.B. durch Textvergrößerung nicht mehr nebeneinander in das Menü passen - stattdessen bleiben sie in einer Reihe stehen und "sprengen" das Menü, genau wie ein "endlos" langes Wort. Eine weitere Möglichkeit wäre z.B. margin-right: -.25em; für #navi li, aber auch das ist keine gute Lösung, da nicht alle Browser identische default-Werte für den Abstand der inline dargestellten <li> zueinander haben.

Daher ist die sinnvollste Methode zur Entfernung der kleinen horizontalen Zwischenräume, #navi li ohne width-Deklaration floaten zu lassen (siehe nächster Abschnitt), denn bei Blockelementen wirkt sich Quelltext-Whitespace natürlich nicht mehr aus.

12.2) Die float-Variante

Die horizontale Menü-Darstellung per Float bietet einige Vorteile, da man es ausschließlich mit Blockelementen zu tun und dadurch mehr Kontrolle über ihre Darstellung hat. #navi li floatet links und kann beispielsweise eine Breite bekommen (die für Links mit längeren Texten auch nach dem Prinzip #navi li.breit anpassbar ist, oder vollständig individuell per ID), und die als Block dargestellten Links nehmen automatisch die volle Breite von #navi li ein.

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	list-style: none;
	}

#navi li {
	float: left;
	width: 5em;
	}

#navi a,
#navi strong {
	display: block;
	text-align: center;
	padding: 0.5em;
	}
Dies funktioniert in allen Browsern außer dem IE < 7, in dem die Links nicht über die volle Breite von #navi li anklickbar sind. Abhilfe schafft auch hier wieder hasLayout für #navi a.

Ab CSS 2.1 darf auch ohne width gefloatet werden, und damit kann das sogenannte "shrink-to-fit-width"-Verhalten genutzt werden: Floatende Elemente ohne width-Deklaration werden auf eine ihrem Inhalt entsprechende Minimalbreite "zusammengeschrumpft" (vergleichbar mit Tabellenzellen, wenn weder für sie noch für <table> eine Breite definiert ist).

Achtung: Zwar verhalten sich IE/Win ab 5.0, Gecko ab Netscape 7.0, Opera ab 7.0 und Safari hier grundsätzlich identisch (bei mehreren Wörtern innerhalb des Menülinks kann es zwar in absoluten Ausnahmefällen einen Zeilenumbruch geben, jedoch kann diesem mit white-space: nowrap; vorgebeugt werden), aber der IE für Mac stellt Floats ohne width über die volle Breite ihres Elternelements dar, so dass bei einem horizontalen Menü die Menülinks untereinander stehen (als würde ihnen die float-Eigenschaft fehlen).

Zu dieser Darstellung kommt es übrigens auch im IE < 7, wenn #navi a display: block; hat und hasLayout gesetzt ist, es allerdings keine width-Deklaration hat. In diesem Falle schafft Abhilfe, außer <li> auch <a> zu floaten (natürlich ebenfalls ohne width). Ich empfehle übrigens, bei ohne width floatenden <li> immer auch <a> ohne width floaten zu lassen, auch für den IE 7.

Zuguterletzt ist bei der Float-Variante in jedem Falle wichtig, dass #navi die innerhalb floatenden #navi li einschließt. Dazu gibt es zwei gute Möglichkeiten:

1. #navi floatet ebenfalls (Prinzip "Float Nearly Everything"). Bei dieser Variante sollte #navi unbedingt eine Breite bekommen (u.a. wegen älterer Opera-Versionen), und falls auf #navi ein nicht floatendes Element folgt, braucht dieses ein "clear".

2. Falls man #navi nicht floaten lassen möchte, kann auch "Easy Clearing" auf #navi angewandt werden (siehe oben, Punkt 2 von mazzos Posting, sowie mein nächster Abschnitt).

12.3) Anmerkungen zum "Easy Clearing"

"Easy Clearing" (auch als "Clearfix" bekannt) wird von vielen Leuten als kompliziert und/oder "dirty" empfunden, was in erster Linie an der Berücksichtung des IE-Mac liegt, die einige Zusatz-Hacks erfordert. Da sie allerdings nur Sinn ergibt, wenn ein CSS-Autor den IE-Mac auch in allen übrigen (CSS-)Belangen berücksichtigt (und folgerichtig auch in diesem Browser testet), dies aber kaum noch jemand tut, stelle ich nachfolgend eine Variante vor, die den IE-Mac außenvor lässt und dadurch wesentlich kürzer und leichter verständlich wird. Außerdem füge ich noch zwei Deklarationen hinzu, die zeitweilig auftretende Probleme beheben.

Vorab noch eine Erklärung, wie "Clearfix" überhaupt funktioniert: Das Pseudo-Element :after fügt unmittelbar vor dem schließenden tag (z.B. </div>) des Elementes, auf das es angewandt wird, einen Inhalt ein. Stellt man diesen als Block dar und lässt ihn clearen, ist der Effekt derselbe, als hätte man im Markup ein leeres, clearendes div eingefügt. Zwar kennt der IE < 8 :after nicht, doch lässt er ein Element seine enthaltenen Floats einschließen, wenn für dieses Element hasLayout gesetzt ist.

Die allgemein bekannte clearfix-"Grundregel" ist folgende:

Code:
.clearfix:after {
	content: ".";
	display: block;
	height: 0;
	clear: both;
	visibility: hidden;
	}
Durch die Höhe 0 passt der Punkt nicht mehr in das Element und wird daher unter diesem dargestellt. Dies ist in der Regel kein Problem, da er ja unsichtbar ist, doch in manchen Konstellationen verschafft er sich Platz und verursacht dadurch Fehldarstellungen. Abhilfe schafft die Hinzunahme von font-size: 0; und overflow: hidden;. Diese Deklarationen machen zwar für ältere Gecko-Browser eine Höhe > 0 erforderlich, jedoch reicht bereits der Wert 0.1px, der genauso wie der Wert 0 dargestellt wird, aber dennoch für ältere Geckos seinen Zweck erfüllt.

Die komplette Regel lautet also:

Code:
.clearfix:after {
	content: ".";
	display: block;
	height: .1px;
	clear: both;
	visibility: hidden;
	font-size: 0;
	overflow: hidden;
	}
Damit schließt das betreffende Element seine enthaltenden Floats in allen Browsern inkl. IE 8 ein, nur für IE 7 und kleiner muss für das Element noch hasLayout gesetzt werden, daher ergänzt man sein IE-CSS z.B. wie folgt:

Code:
.clearfix {
	min-height: 0;
	}

* html .clearfix {
	height: 1px;
	}
Wer den IE 5.0 ignoriert, benötigt sogar nur eine Regel:

Code:
.clearfix {
	zoom: 1;
	}
(denn wie bereits erwähnt, kennt der IE die Eigenschaft "zoom" erst ab Version 5.5.)

Übrigens sehe ich oft eine unbedachte bzw. unnütze Verwendung der clearfix-Klasse: Man muss im HTML-Code nicht z.B. <ul id="navi" class="clearfix"> schreiben, wenn man im CSS auch #navi:after schreiben und sich dadurch die Klasse im HTML sparen kann. Durch Kommatrennung können der clearfix-Regel beliebig viele Selektoren hinzugefügt werden (z.B. #navi:after, #content:after etc.). Für den IE < 8 müssen dann nur noch die betreffenden Elemente hasLayout bekommen - sofern das überhaupt noch nötig ist, denn hat ein Element z.B. bereits eine width-Deklaration, ist hasLayout ohnehin bereits gesetzt.

13) Ohne width gefloatet und dennoch horizontal zentriert

Möchte man seine ohne width gefloateten Menüpunkte nun horizontal zentrieren, steht man vor dem Problem, dass dies bei Floats natürlich nicht ohne weiteres möglich ist. Es gibt mehrere mögliche Lösungen, von denen ich 2 erklären werde. Diese basieren respektive auf folgenden Eigenschaften:

1. display: table;
2. display: inline-block; (diese Variante ist allerdings vor allem in Firefox < 3 unter Umständen instabil)

13.1) Die display-table-Variante

(Vorab sei bemerkt, dass die nachfolgende Methode auf Stu Nicholls | CSSplay | Centering Floats basiert, aber dennoch anders ist - Dank geht dabei auch an fricca )

Diese Variante nutzt die display: table-Eigenschaften, damit #navi auf die Breite zusammenschrumpft, die die enthaltenen Links erfordern, so dass #navi anschließend per margin: 0 auto; horizontal zentriert werden kann.

Ein Bug im Firefox erzwingt bei dieser Variante ein zusätzliches div, denn wie auf der verlinkten Seite beschrieben, kann es dem angedachten CSS-Konstrukt widerfahren, dass der Firefox die li-Elemente zweizeilig anordnet, und um dies zu verhindern, muss eine "echte" Tabellenzeile her, die die Darstellung der li-Elemente in einer Reihe erzwingt. Diesen wird im Zuge dessen auch das float genommen und durch display: table-cell; ersetzt, um eine saubere CSS-Tabelle zu bekommen. Das geänderte Markup sieht folgendermaßen aus:

Code:
<div id="navi">
<ul>
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
</div>
Und das dazugehörige CSS:

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	display: table;
	margin: 0 auto;
	}

#navi ul {
	display: table-row;
	}

#navi li {
	display: table-cell;
	}

#navi a,
#navi strong {
	display: block;
	padding: 0.5em;
	}
Doch leider stellt sich auch hier wieder der IE (inkl. 7, jedoch nicht 8 ) quer, da er sämtliche table-Eigenschaften nicht kennt, so dass für ihn ein anderer Ansatz gefunden werden muss. Ein mit display: inline-block; vergleichbares Verhalten wäre hilfreich (sowohl für ul als auch li), und dieses kann im IE auch tatsächlich durch display: inline; zusammen mit zoom: 1; erzeugt werden. Letzteres kennt zwar der IE 5.0 nicht, doch wird bei diesem ein äquivalentes Verhalten durch das bereits bekannte height: 1px; ausgelöst. Folgende Zusatz-Regeln sind nötig und dürfen nur vom IE gelesen werden:

Code:
#navi {
	text-align: center;
	}

#navi ul,
#navi li {
	display: inline;
	zoom: 1;
	}

#navi a,
#navi strong {
	float: left;
	}

* html #navi ul,
* html #navi li {
	height: 1px;
	}
Da diese CSS-Tabelle in standardkonformen Browsern natürlich auch bei Überbreite keinen Umbruch der <li> zulässt, kann man dem IE-CSS noch white-space: nowrap; für ul zuweisen, so dass sich der IE auch in dieser Hinsicht äquivalent zu den übrigen Browsern verhält (ausgenommen der IE 5.0, der die Eigenschaft white-space nicht kennt).

Noch ein allgemeiner Hinweis zu dieser Navigation: Falls sie trotz zentrierter Links immer die volle verfügbare Breite einnehmen soll (z.B. für eine durchgehende Hintergrundfarbe), ist das zusammengeschrumpfte #navi natürlich zu schmal. Abhilfe schafft ein div, das um #navi gelegt wird. Zwar sollte man nach Möglichkeit nie einzelne Elemente mit einem div umgeben (wenngleich dies hier bei der Navigationsliste leider unvermeidbar ist), aber da es u.a. für die Nutzer von Screenreadern sinnvoll ist, auch die Navigation mit einer Überschrift zu versehen, wäre folgendes Markup bestens geeignet:

Code:
<div id="navi">

<h2>Navigation</h2>

<div>
<ul>
<li><a href="#">Link 1</a></li>
<li><a href="#">Link 2</a></li>
<li><a href="#">Link 3</a></li>
</ul>
</div>

</div>
Die Selektoren der vorigen CSS-Beispiele müssen dann natürlich angepasst werden (Stichwort "Nachfahrenselektor").

Möchte man die h2 vor den Nutzern grafischer Browser verstecken, tut man dies einfach durch

Code:
#navi h2 {
	position: absolute;
	left: -9999px;
	top: -9999px;
	}
display: none; wäre zwar ebenfalls möglich, jedoch wird die Überschrift dann von diversen Screenreadern nicht mehr vorgelesen.

13.2) Die inline-block-Variante

Vorab sei gesagt, dass ich persönlich diese Variante nach Möglichkeit nicht verwende, da sie (wie bereits erwähnt) vor allem in Firefox < 3 unter Umständen instabil ist - spätestens, wenn eine Sub-Navigation hinzugefügt wird, wird das Ganze sehr problematisch. Eine Variante, die auch in Firefox < 3 unter allen Umständen stabil ist, ist zwar möglich, aber wäre extrem aufwendig und ohne weitere Elemente innerhalb der <li> kaum zu realisieren. Auf http://www.brunildo.org/test/indext1.shtml ist eine stabile Variante zu sehen, die für dortigen Zweck natürlich ideal ist, aber meiner Meinung nach für eine Navigation übertrieben wäre, solange es auch einfachere Möglichkeiten gibt, die zum gleichen Ergebnis führen.

Aber trotz allem, für ein Menü mit nur einer Ebene ist die inline-block-Methode auch in "einfacher Ausführung" problemlos geeignet, und daher nun ihre Beschreibung: Sie verwendet display: inline-block; statt float für #navi li, so dass diese (trotz enthaltener Links mit display: block; ) nebeneinander stehen und darüberhinaus per text-align: center; für #navi horizontal zentriert werden können. Übrigens ist bei dieser Variante (im Gegensatz zur zuvor beschriebenen table-Methode) im Falle von Überbreite auch ein Zeilenumbruch der Menüpunkte möglich.

Allerdings müssen bei dieser Variante auch die Quelltext-Whitespaces zwischen den einzelnen <li> entfernt werden, da andernfalls die bereits erläuterten kleinen horizontalen Abstände zwischen den <li> entstehen würden, die sich per CSS nicht zuverlässig entfernen lassen. Man kann die Whitespaces entweder auskommentieren, oder alle <li> in dieselbe Zeile schreiben, oder den Zeilenumbruch früher machen:

Code:
<ul id="navi">
<li><a href="#">Link 1</a></li
><li><a href="#">Link 2</a></li
><li><a href="#">Link 3</a></li>
</ul>
Einen "Schönheitspreis" wird man natürlich für keine der 3 genannten Varianten gewinnen Aber alle 3 sind valide und funktional, und damit auch völlig legitim.

Das zugehörige CSS sieht folgendermaßen aus:

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	list-style: none;
	text-align: center;
	}

#navi li {
	display: -moz-inline-box;
	-moz-box-orient: vertical;
	display: inline-block;
	vertical-align: top;
	}

#navi a,
#navi strong {
	display: block;
	padding: 0.5em;
	position: relative;
	outline: none;
	}
Die ersten beiden Deklarationen von #navi li sind für Firefox < 3, der display: inline-block; noch nicht kennt, und vertical-align: top; dient in erster Linie Opera < 9, der andernfalls den <li> eine Unterlänge verpasst.

Bei #navi a dient position: relative; dazu, dass sich in Firefox < 1 die gesamte Link-Fläche hovern und anklicken lässt, und dass Opera < 7.5 z.B. eine Hintergrundfarbe für die Links akzeptiert. outline: none; entfernt die Fokus-Outline, deren Erscheinen in Firefox < 3 leider dazu führen würde, dass ein angeklickter Link sein umgebendes <li> (und damit die gesamte Navigation) vertikal ausdehnt.

Und da sich auch bei dieser Variante der IE < 8 querstellt (er kennt display: inline-block; nicht), muss ihm das gewünschte Verhalten auf dieselbe Weise beigebracht werden, die im vorigen Abschnitt (über die Variante per display: table; ) beschrieben wurde. Allerdings sollte <ul> dabei außenvor bleiben - es genügt, die beschriebenen Extra-Regeln für <li> und <a>/<strong> zu übernehmen.

14) Horizontales Menü mit vertikal zentrierten ein- und zweizeiligen Links

Eine Vertikalzentrierung der Linktexte ist kein Problem, solange sie einzeilig sind, doch sobald auch zweizeilige hinzukommen, muss ein deutlich höherer Aufwand betrieben werden. Für alle guten Browser liegt die Lösung in den table-Eigenschaften, die die gewünschte Vertikalzentrierung problemlos ermöglichen. Da der IE < 8 diese Eigenschaften nicht kennt, wird er nach diesem Prinzip dazu gebracht, den Text immer vertikal zentriert darzustellen.

Vorab einige Anmerkungen zu dem nachfolgend gezeigten Code-Beispiel:

1. Auch wenn man möglichst nie einem Element, das Text enthält, eine height-Deklaration geben sollte, ist dies in diesem Falle leider für #navi a nötig, da es keine andere Möglichkeit gibt, alle Links auf dieselbe Höhe zu bringen. Ohne height-Deklaration wären die zweizeiligen Links immer höher als die einzeiligen, und das würde eine Umsetzung des gewünschten Designs unmöglich machen. Verwendet man für height allerdings einen Wert in em und testet das Textzoom-Verhalten seines Menü ausgiebig, ist die height-Deklaration kein Problem.

2. <span> ist für den IE < 8 nötig (damit er den kompletten Text vertikal an <b> ausrichtet, das immer die volle Link-Höhe einnimmt), kann gleichzeitig aber auch sinnvoll für alle guten Browser eingesetzt werden, indem es display: table-cell; bekommt und sein Elternelement #navi a display: table;.

3. Ob man <b> per CC versteckt oder nicht nicht, ist Ermessensache - versteckt man es nicht, ist der Code schlanker, aber dafür steht ein leeres Element im Markup, mit dem einzigen Zweck, dem IE < 8 nachzuhelfen.

Hier nun der komplette Code (die durch die 1px-border strenggenommen nötigen minimalen Boxmodell-Korrekturen für den IE < 6 lasse ich außenvor):

HTML-Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html lang="de" xml:lang="de" xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Menü-Beispiel</title>
<style type="text/css">

* {
	margin: 0;
	padding: 0;
	border: none;
	font: 100%/1.3 Arial, sans-serif;
	text-decoration: none;
	}

body {
	font-size: .8em;
	padding: 15px;
	}

ul {
	list-style: none;
	width: 37.5em;
	float: left;
	background: #ffd500;
	color: inherit;
	border: 1px solid #000;
	padding-left: 7em;
	}

li {
	float: left;
	width: 6em;
	border-left: 1px solid #000;
	}

#last {
	border-right: 1px solid #000;
	}

li * {
	text-align: center;
	vertical-align: middle;
	}

a,
strong {
	display: table;
	width: 100%;
	height: 3.5em;
	background: #c00;
	color: #fff;
	}

span {
	display: table-cell;
	padding: 0 1em;
	}

a:hover,
strong {
	background: #fff;
	color: #000;
	}

</style>
<!--[if lt IE 8]>
<style type="text/css">

a,
strong {
	display: block;
	width: auto;
	padding: 0 1em;
	}

span,
b {
	zoom: 1;
	padding: 0;
	}

a span,
a b {
	cursor: pointer;
	}

b {
	height: 100%;
	}

* html ul {
	width /**/: 44.5em;
	}

* html a span,
* html a b {
	cursor /**/: hand;
	}

* html span {
	height /**/: /**/1px;
	}

</style>
<![endif]-->
</head>

<body>

<ul>
<li><a href="#"><span>Text</span><!--[if lt IE 8]><b></b><![endif]--></a></li>
<li><strong><span>Text</span><!--[if lt IE 8]><b></b><![endif]--></strong></li>
<li><a href="#"><span>mehr Text</span><!--[if lt IE 8]><b></b><![endif]--></a></li>
<li><a href="#"><span>Text</span><!--[if lt IE 8]><b></b><![endif]--></a></li>
<li id="last"><a href="#"><span>Text</span><!--[if lt IE 8]><b></b><![endif]--></a></li>
</ul>

</body>

</html>
15) Grafische Menüs

Ein Menü, das seinen Text in Form von Hintergrundgrafiken enthält, hat den Nachteil, dass für Besucher, die in ihrem Browser das Laden von Grafiken deaktiviert haben, keinerlei Link-Texte mehr sichtbar wären und die Seite daher nicht mehr navigierbar wäre. Eine einfache Abhilfe wäre natürlich, die Grafiken als <img> mit "alt"-Attribut einzubinden, aber das widerspricht der Trennung von Inhalt und Design, denn bereits eine Grafik mit spezieller Schrift (ganz zu schweigen von zusätzlichen Schatten oder ähnlichen Effekten) ist ausschließlich ein Design-Mittel und gehört daher nicht ins Markup, sondern ins CSS.

Doch es gibt glücklicherweise auch die Möglichkeit, zwar Hintergrundgrafiken zu verwenden, aber dennoch bei deaktivierten Grafiken den regulären Link-Text anzeigen zu lassen: Durch die "Gilder/Levin-Methode", auf der meine nachfolgend erläuterte Variante basiert. Diese stellt das Menü in horizontaler Form dar (da diese Variante aufwendiger ist, so dass sie für die vertikale Darstellung nur noch vereinfacht werden muss).

Als erstes bekommt jedes Element #navi li seine eigene ID, da ja später individuelle Hintergrundgrafiken zugewiesen werden sollen:

Code:
<ul id="navi">
<li id="home"><strong>Home<span></span></strong></li>
<li id="team"><a href="#">Team<span></span></a></li>
<li id="kontakt"><a href="#">Kontakt<span></span></a></li>
</ul>
Dann wird #navi li links gefloatet, und kann dank seiner ID auch eine individuelle Breite bekommen, falls die Links der Länge ihres jeweiligen Textes angepasst werden sollen. Eine Höhe benötigt #navi li nicht, da diese durch die Höhe des enthaltenen <a> bestimmt wird. <a> bekommt außerdem noch width: 100%; sowie position: relative;, da sich <span> (das im folgenden Absatz in Erscheinung treten wird) hinsichtlich Größe und Positionierung auf sein Elternelement <a> beziehen muss.

Code:
#navi li {
	float: left;
	width: 50px;
	}

#navi #kontakt {
	width: 60px;
	}

#navi a,
#navi strong {
	display: block;
	height: 30px;
	width: 100%;
	position: relative;
	}
Jetzt kommt <span> ins Spiel. Es soll sich über die gesamte Link-Fläche erstrecken, und diese (samt dem regulären Link-Text) mit einem Hintergrundbild überdecken (das natürlich keinerlei Transparenz enthalten darf). Fehlt das Bild (z.B. bei vom Besucher deaktivierten Grafiken), ist der darunter liegende Text dagegen uneingeschränkt sichtbar.

Als erstes wird nun eine allgemeine Regel aufgestellt, so dass anschließend nur die noch Regeln für die Anzeige der individuellen Hintergrundgrafiken benötigt werden.

Code:
#navi span {
	position: absolute;
	width: 100%;
	height: 30px;
	top: 0;
	left: 0;
	background: url(navi.png);
	}
Anmerkung: Wegen eines Bugs in Opera 8.x wird hier bewusst auf (das prinzipiell naheliegende) "no-repeat" verzichtet, denn andernfalls zeigen diese Opera-Versionen beim ersten Aufruf der Seite die Grafik nur bei dem <span> an, für das background-position: 0 0; deklariert ist, während sie bei allen übrigen <span>-Elementen erst z.B. beim Scrollen der Seite oder beim Hovern der Links erscheint. Das Fehlen von "no-repeat" ist kein Problem, da ohnehin nur ein kleiner Ausschnitt der Grafik zu sehen ist, so dass es egal ist, ob sie sich außerhalb des sichtbaren Bereiches nun wiederholt oder nicht.

Da empfohlen wird, zu Gunsten einer optimalen Website-Performance die Anzahl der HTTP-Anfragen zu reduzieren (sprich: durch möglichst wenig zu übertragende Dateien), bietet es sich an, alle Grafiken zu einer einzigen zusammenzufassen (die im vorstehenden CSS-Code schlicht "navi.png" heißt), und den jeweils gewünschten Teil per background-position in den sichtbaren Bereich des dazugehörigen Links zu rücken. Weitere Vorteile dabei: Es ist keinerlei Preload für die Hover-Effekte mehr nötig, und die Dateigröße einer Grafik, die alle Zustände enthält, ist auch geringer als die Summe der entsprechenden Einzel-Grafiken (u.a. da es insgesamt nur einen Grafik-Header gibt).

In dieser Link-Grafik können z.B. in der oberen Reihe alle Link-Texte nebeneinander stehen. Diese Reihe wird dann dupliziert und nach unten versetzt, und bekommt dort z.B. die geänderte Farbe für die Hover-Effekte, so dass man auf der fertiggestellten Grafik schließlich das gesamte Menü zweimal sieht, z.B. einmal oben mit weißem Text, und darunter noch einmal mit rotem Text.

Nun muss die Grafik nur noch für jeden einzelnen Link sowie seinen Hover-Effekt an die richtige Position gebracht werden. Dies geschieht nach folgendem Prinzip:

Code:
#navi #home a span {
	background-position: 0 0;
	}

#navi #home a:hover span,
#navi #home strong span {
	background-position: 0 -30px;
	}
Natürlich sollte man aber auch den von der Grafik verdeckten Text nicht vernachlässigen, denn unter Umständen ist dieser ja sichtbar (in jedem Falle aber während des ersten Aufrufs der Website, d.h. bevor die Navi-Grafik geladen wurde und sich anschließend im Browser-Cache befindet). Der reguläre Link-Text wird also wie gewohnt formatiert (möglichst passend zu den Grafiken), und damit er bei Textvergrößerung nicht irgendwann unter der span-Grafik hervorschaut, bekommt #navi a noch overflow: hidden;.

Der CSS-Code sieht schließlich wie folgt aus:

Code:
* {
	margin: 0;
	padding: 0;
	}

#navi {
	list-style: none;
	float: left;
	width: 100%;
	}

#navi li {
	float: left;
	width: 50px;
	}

#navi #kontakt {
	width: 60px;
	}

#navi a,
#navi strong {
	display: block;
	height: 30px;
	width: 100%;
	position: relative;
	overflow: hidden;
	}
	
#navi span {
	position: absolute;
	width: 100%;
	height: 30px;
	top: 0;
	left: 0;
	background: url(navi.png);
	}

#navi #home a span {
	background-position: 0 0;
	}

#navi #home a:hover span,
#navi #home strong span {
	background-position: 0 -30px;
	}
Aber es wäre ja fast schon ein Wunder, wenn der IE damit bereits zufrieden wäre Und tatsächlich: Obwohl sich span innerhalb von #navi a befindet, zeigt der Cursor des IE (inkl. 7, jedoch nicht 8 ) beim Link-Hovern nicht mehr die übliche "Hand-Form". Diese muss ihm also wieder "beigebracht" werden, durch

Code:
#navi a span {
	cursor: pointer;
	}
Übrigens kann dieses Problem natürlich auch noch an anderen Stellen der Website auftauchen, und daher kann man letztlich sogar ein pauschales a * { cursor: pointer; } einsetzen.

Und auch der IE 5.x schießt hier noch einmal quer, denn er kennt den Wert "pointer" nicht - er möchte hier "hand" gesagt bekommen. Dieser Wert ist zwar leider kein gültiges CSS, aber wie bereits weiter oben gesagt: Da das entsprechende CSS dem IE per Conditional Comment zugewiesen wird, kann man darüber hinwegsehen - der CSS-Validator tut dies schließlich auch

Und zuguterletzt gibt es noch einen ärgerlichen Bug des IE 6, der Hintergrundgrafiken beim Hovern "flackern" lässt. Achtung: Er tut dies nur bei einer bestimmten Einstellung des IE, also selbst wenn beim abschließenden Test nichts flackert, bei anderen Nutzern wird dies definitiv passieren! Alle Infos zu diesem Problem stehen auf http://www.fivesevensix.com/studies/ie6flicker/, und ebenso die Ideallösung per .htaccess (zu finden unter "Update - 06/03/2004").

Geändert von heiko_rs (14.12.2010 um 03:18 Uhr)
Mit Zitat antworten
Sponsored Links