CSS-Trick: Navigation gleichmäßig über die gesamte Breite ausrichten

Das wohlverteilte Menü

Bei meinem letzten Kundenprojekt hatte ich eine kleine CSS-Kniffelei zu lösen: Das Navigationsmenü sollte sich horizontal über die Seite verteilen – mit gleichmäßigen Abständen zwischen den Menüpunkten – und zwar auf dem Pixel genau!

Update: „auf dem Pixel genau“ stimmt nicht immer. Es kann manchmal durch die Abstandsberechnung ein „Ausgleichspixel“ geben. – siehe dazu: Spivs Hinweis in den Kommentaren.

Der erste Menü-Punkt beginnt am linken Rand und der letzte Menü-Punkt endet mit dem letzten Zeichen am rechten Rand.

CSS-Trick am Kundenbeispiel

Beispiel einer Seite mit gleichmäßig über die gesamte Breite ausgerichteten Navigationsmenü



Die Abstände zwischen den Menü-Punkten bleiben übrigens immer gleich. Sogar wenn man die Fenstergröße ändert.

Das Prinzip

Diese Aufgabe ist im Prinzip leicht zu lösen. Man muss die Navigation nur als Blocksatz ausrichten.

[css gutter=“false“]
ul { text-align: justify; }
[/css]

Das Problem

Allerdings funktioniert die horizontale Ausrichtung als Blocksatz nur bei mehrzeiligen Text. Bei meinem Kundenprojekt war die Navigation aber einzeilig. In diesem Fall würden die Menüpunkte nicht als Blocksatz, sondern zentriert ausgerichtet, weil das übergeordnete Element zentriert war.

Wir wollen aber Blocksatz haben! – Was nun?

Der Trick (Markup-Update)

Ganz einfach: Man gaukelt dem Browser einen mehrzeiligen Text vor. Dann wird das Menü – wenn es in der ersten Zeile steht – als Blocksatz angezeigt. Um das zu erreichen, habe ich dem letzten Menüpunkt einfach ein li-Element mit einem Leerzeichen angehängt. Diesem Element habe ich im Stylesheet mit dem padding-left-Attribut eine Überbreite gegeben, so dass es auf jeden Fall nach dem Menü einen Zeilenumbruch erzwingt und in die zweite Zeile rutscht. Und schon haben wir mehrzeiligen Text!

[css gutter=“false“]
li #line { padding-left: 100%; }
[/css]

Der Leser bekommt von der Mehrzeiligkeit nichts mit, weil das li-Element leer ist und wir normalerweise ohnehin etwas Platz unter dem Menü brauchen. ;-)

Demo und Beispielcode

Auf meiner Demo-Seite “Das wohlverteilte Menü” könnt Ihr den CSS-Trick studieren, kopieren und weiterverarbeiten.

Update 14.07.2012

Aus gegebenen Anlass habe ich eine zweite Demo-Version hoch geladen: Jetzt hat das Menü einen farbigen Hintergrund. Hier geht es zur Version 2 mit farbigen Hintergrund.

Update 04.09.2012

Peter hat mich in seinem Kommentar darauf aufmerksam gemacht, dass etwas mit dem Markup nicht ok ist. Das habe ich verbessert. Die beiden Demo-Versionen (mit und ohne Hintergrund) sind jetzt valide.

This entry was posted on by .

Heiko Mamerow

Buddhist, Vater, Freund, Internetseitenbauer, Sportler, Musikliebhaber & Verkehrsteilnehmer ;-)

36 Gedanken zu „CSS-Trick: Navigation gleichmäßig über die gesamte Breite ausrichten

  1. Spiv

    Allerdings ist das mit den gleichen Abständen der Menüpunkte untereinander pixelgenau im Zweifelsfall nicht 100% umsetzbar, denn die komplette Menübreite muss ohne nachkommastelle durch die Anzahl der Menüpunkte teilbar sein, da ein Pixel nunmal nicht teilbar ist. Deswegen wird es im Zweifelsfall immer einen „Ausgleichspixel“ geben.

    Antworten
    1. Heiko Mamerow Beitragsautor

      Hallo Spiv, vielen Dank für den Hinweis. Ich werde einen Hinweis einfügen. Aber nicht mehr heute. Ich „muss“ gleich wieder mit meinem Sohn die Haie im Mittelmeer verscheuchen… ;-)

      Antworten
  2. André

    Danke, für die ausführliche Erklärung!!! Der Trick funktioniert aber nicht, wenn man das Menü eine Hintergrundfarbe hat. Dann dehnt sich die Hintergrundfarbe nach unten aus, oder?

    Viele Grüße,
    André

    Antworten
    1. Heiko Mamerow Beitragsautor

      Hallo André,

      …genau. Wenn man für die Liste eine Hintergrundfarbe festgelegt hat, dann wird die erzwungene Zeile sichtbar.

      Das lässt sich aber mit einem kleinen Workaround beheben:
      Umschließe das Listen-Element-Bündel mit einem span-Element. Für dieses span-Element legst du die gewünschte Hintergrundfarbe für das Menü fest. Das war es schon. Wenn das Menü bzw. Liste auch noch einen inneren Abstand zur farbigen Box haben soll, kannst Du das im span-Style zuweisen.

      Also im Prinzip legst Du die Styles, die Du bisher dem ul-Element zugewiesen hast auf das neue span-Tag um.

      (Nicht vergessen: Die ursprüngliche Hintergrundfarbe aus dem ul entfernen und die beiden span-Elemente müssen natürlich eine eigene Klasse oder ID bekommen…)

      Antworten
        1. Martin Piontek

          Ich habe das Problem anders gelöst. Ich habe meine Liste einfach ein margin-bottom von -1em gegeben und somit die Listenhöhe um die leere Zeile verringert :)

          Antworten
  3. Hannes

    Hallo Heiko.
    danke für die Anleitung!

    Ich habe probiert diese Anleitung auf meiner Webiste umzusetzen, aber leider hat es nicht funktioniert.

    Ich wäre dir sehr dankbar wenn du bitte mal nachsehen könntest, welcher der css-Befehle Probleme macht?

    Antworten
    1. Heiko Mamerow Beitragsautor

      Hallo Hannes,
      für li und span musst Du „display: inline-block;“ zuweisen. Dann ist schon mal die Navigation horizontal. Außerdem solltest Du zwischen den li-Tags ein Leerzeichen setzen… ;-)

      Antworten
  4. Peter

    Nette Idee!
    Aber es ist leider dann etwas sehr merkwürdiges und unschönes Markup.

    Wenn es eine andere Lösung dazu gäbe die standardkonform ist, würde ich es sicherlich auch nutzen. Mal sehen, vielleicht findet sich ja was.

    Antworten
  5. Timo

    Ich habe die Idee noch ein wenig verfeinert, um das Markup im HTML nicht mit einem leeren Listenelement zu stören.
    Der Trick ist ganz einfach: Pseudoelemente, die schon seit CSS2.1 funktionieren.

    Das letzte Listenelement wird um ein ::after ergänzt, somit ergibt sich

    ul { list-style-type: none; text-align: justify; }
    li { list-style: none; display: inline; }
    li:last-of-type::after { content: “; padding-left: 100%; display: inline-block; }

    Statt der Pseudoklasse :last-of-type kann man natürlich auch dem letzten Listenelement eine Klasse zuweisen, aber so ist es doch noch ein wenig schöner, da im HTML-Quelltext nichts darauf hindeutet. Alles konform und Crossbrowser-kompatibel.

    Antworten
    1. Marco

      Hallo Timo

      Vielen Dank für IhreLösung, welche durchaus sehr interessant tönt. Ich habe dies nun versucht, doch leider hat es nicht geklappt.

      Haben Sie eventuell spontan eine Idee, woran es liegen könnte resp. wo ich am besten noch genauer kontrollieren soll in meinem Quelltext?

      Falls Interesse besteht, sende ich Ihnen gerne den Code zu..

      Liebe Grüsse.

      Antworten
  6. martin

    Hey Heiko,

    erstmal danke für den tollen Tipp! Sagmal ich hoffe ich stelle mich nicht zu doof an … aber, ich hau den code doch einfach nur in meine style.css (vom child theme) rein, oder?

    Bei mir ändert sich da einfach nichts…

    Antworten
  7. Kagu

    Hoi…

    um das ganze etwas zu ergänzen ^-^
    Wer die einzelnen List-Elemente nochmals mit einem eigenen Background hinterlegen möchte, und diese Kästen alle dieselbe Größe haben sollen, muss das Element innerhalb des „li“-Elements wiederum in einen „div“ packen, welcher eine eigene Klasse bekommt (bei mir colored) und den Elementen dann darüber die Background-Color zuweißen. Auch muss dann noch eine Breiten-Angabe hinzu. So hat man schön verteilt gleich große Kästen, welche das jeweilige Element darstellen :)

    Zu sehen ist das ganze dann hier:
    http://inyo-dream.lima-city.de/osc/
    (Testseite, Designentwurf… ^-^)

    Antworten
    1. Heiko Mamerow Beitragsautor

      Hallo Kai, Du brauchst das div-Element nicht. Den „Button-Effekt“ kannst Du z.B. auch mit dem a-Tag erreichen, wenn Du es als Block-Element deklarierst und die Hintergrundfarbe usw. dort zuweist.

      Antworten
  8. Stefano

    Hallo

    Danke für diesen coolen Trick :) Ich habe alle deine Einstellungen übernommen und hat super geklappt :)

    Das gleiche habe ich mit einem Array und einer foreach-Schleife versucht. Keine Chance. Es will so nicht bei mir… Ich bin seit ungelogen zwei Stunden daran und komme nicht weiter. Würde mich freuen, wenn mir jemand helfen könnte… Ich kann nicht loslassen.

    Bei Interesse kann ich euch meine Schleife senden. Sie hier zu posten, wäre vielleicht nicht so angebracht. Ist ja schliesslich kein Forum :)

    Danke aus der Schweiz

    Antworten
    1. Heiko Mamerow Beitragsautor

      Hallo Stefano, freut mich, dass der „Trick“ Dir geholfen hat. :-)

      Für das Problem mit der Schleife kann ich Dir empfehlen, mal bei „Stack Overflow“ zu stöbern und ggfls. dort anzufragen: http://stackoverflow.com/ Ich selber habe noch kein Problem gehabt, was dort nicht schon angefragt wurde bzw. gelöst. TOI-TOI-TOI!

      Antworten
  9. Max

    Hallo,
    ich habe leider kleine Probleme bei der Umsetzung weil ich mich bisweilen mit CSS überhaupt nicht befasst habe :s. Meine HTML- Kenntnisse helfen mir nicht mehr.
    Ich würde in meinem Blog gerne genau wie du beschrieben hast diese Leiste im Blocksatz ausrichten. Dafür hab ich die Funktion „CSS-Einfügen“ aufgerufen. Da öffnet sich dann ein Textfeld um benutzerspezifisches CSS hinzuzufügen. Die Befehle funktionieren allerdings nicht ( ul { text-align: justify; } und li #line { padding-left: 100%; } ) . Was mache ich falsch? :D

    Btw.: ich habe zuerst versucht das ganze zu zentrieren mit den Befehlen:
    .PageList {
    text-align:center !important;
    }
    .PageList li {
    display:inline !important;
    float:none !important;
    }.

    Das hat auch funktioniert, sieht aber bescheiden aus.

    Vielen Dank im Voraus für eine deppeneinfache Lektion CSS :P

    lg

    Antworten
  10. rod

    Hallo zusammen,

    der Trick klappt super. Leider habe ich nun aufgrund des letzten li- Platzhalters eine leere Zeile, die sich in einem größeren Abstand zum nächsten Objekt bemerkbar macht. Gehe ich recht in der Annahme, dass sich das nicht vermeiden lässt? Oder it die Optimierung von Timo dafür die Lösung? Leider bekomme ich diese Optimierung einfach nicht hin.
    Was ist mit „Das letzte Listenelement wird um ein ::after ergänzt, somit ergibt sich“ gemeint? Ist das das Dummy-Li-Element oder das wirklich letzte in der Liste?

    Gruß, Rod

    Antworten
  11. Ingo

    Hallo,
    sehr schöne Idee – leider scheint es aber damit ein Problem in Joomla zu geben:
    Wenn ich eine Navi nach obigem Muster direkt in die index.php meines Templates schreibe (mit der dazugehörigen CSS), dann funktioniert alles prima. Wenn ich jetzt anstelle dieser den entsprechenden Joomla Code für ein Modul einsetze und das Ganze über das Backend mit Menü-Einträgen versehe, dann sieht in meinem Frontend der HTML-Code von und zwar genauso aus, allerdings verteilt sich die Navi nicht über die Breite, sondern bleibt zusammen „kleben“. Es scheint, dass Joomla einfach alle Zwischenräume (Whitespace) ignoriert.
    Hat da jemand eine Idee zu? Für Tipps wäre ich dankbar :-)

    Antworten
    1. Ingo

      … ah, ich sehe gerade, dass meine Tags im Text fehlen – es muss heißen:

      „Wenn ich jetzt anstelle dieser ul-Liste den entsprechenden Joomla Code für ein Modul einsetze…“

      und

      „…dann sieht in meinem Frontend der HTML-Code von ul und li zwar genauso aus,…“

      Antworten
      1. Jan

        Hallo Ingo,
        Joomla schreibt da nichts rein, dass wäre wenn dann dein Template.
        Aber ohne den genauen Quellcode zu sheen kann man dazu eigentlich keine Hilfe geben.
        Wende dich doch mal an eines der Joomlaforen da kann dir wahrscheinlich besser geholfen werden als hier über die Kommentare.

        Viele Grüße,
        Jan

        Antworten
  12. Marco

    Hallo zusammen,

    Mittlerweile gibt es noch eine weiter Möglichkeit wie man dies relativ einfach hinkriegen kann.
    Die Lösung lautet: Flexbox.

    Für eine Flexbox muss man „display: flex“ nehmen und dann gibt es sehr viele Einstellungen dazu.

    Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.