Jak * naprawdę * uzasadnić poziome menu w HTML+CSS?

Znajdziesz mnóstwo samouczków na paskach menu w HTML, ale dla tego konkretnego (choć ogólnego IMHO) przypadku, nie znalazłem żadnego przyzwoitego rozwiązania:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • istnieje różna liczba pozycji menu tylko tekstowych, a układ strony jest płynny.
  • pierwsza pozycja menu powinna być wyrównana do lewej, ostatnia Pozycja menu powinna być wyrównana do prawej.
  • pozostałe elementy powinny być optymalnie rozłożone na pasku menu.
  • liczba jest różna, więc nie ma szans na wstępne obliczenie optymalne szerokości.

Zauważ, że tabela nie będzie działać również tutaj:

  • Jeśli wyśrodkujesz wszystkie TD, pierwszy i ostatni element nie są wyrównane poprawnie.
  • If you left-align and right-align the first resp. ostatnie elementy, odstępy będą nieoptymalne.

Czy to nie dziwne, że nie ma oczywistego sposobu, aby zaimplementować to w czysty sposób za pomocą HTML i CSS?

 84
Author: Paul D. Waite, 2008-09-08

13 answers

Nowoczesne Podejście- Flexboxy !

Teraz, gdy CSS3 flexboxes mają lepszą obsługę przeglądarki, niektórzy z nas mogą w końcu zacząć z nich korzystać. Wystarczy dodać dodatkowe prefiksy dostawcy dla więcej zasięgu przeglądarki.

W tym przypadku wystarczy ustawić element nadrzędny display na flex, a następnie zmienić justify-content własność do albo space-between lub space-around aby dodać przestrzeń między lub wokół pudełka dziecięcego flexbox pozycji.

Za Pomocą justify-content: space-between - (przykład tutaj):

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-between;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>

Za Pomocą justify-content: space-around - (przykład tutaj):

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-around;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>
 41
Author: Josh Crozier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-26 02:27:24

Najprostszą rzeczą do zrobienia jest zmuszenie linii do zerwania przez wstawienie elementu na końcu linii, który zajmie więcej niż lewa dostępna przestrzeń, a następnie ukrycie go. Udało mi się to dość łatwo osiągnąć za pomocą prostego span elementu w ten sposób:

#menu {
  text-align: justify;
}

#menu * {
  display: inline;
}

#menu li {
  display: inline-block;
}

#menu span {
  display: inline-block;
  position: relative;
  width: 100%;
  height: 0;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 2</a></li>
  </ul>
  <span></span>
</div>

Wszystkie śmieci wewnątrz selektora #menu span jest (o ile znalazłem) wymagane, aby zadowolić większość przeglądarek. Powinna ona wymusić Szerokość elementu span do 100% , co powinno spowodować przerwanie linii ponieważ jest on uważany za element inline ze względu na regułę display: inline-block. inline-block umożliwia również {[2] } blokowanie reguł stylu, takich jak width, co powoduje, że element nie pasuje do menu, a tym samym menu do łamania linii.

Oczywiście musisz dostosować szerokość span do swojego przypadku użytkowania i projektu, ale mam nadzieję, że masz ogólny pomysł i możesz go dostosować.

 83
Author: Asbjørn Ulsberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-03 18:47:10

Ok, To rozwiązanie nie działa na IE6/7, z powodu braku wsparcia dla :before/:after, ale:

ul {
  text-align: justify;
  list-style: none;
  list-style-image: none;
  margin: 0;
  padding: 0;
}
ul:after {
  content: "";
  margin-left: 100%;
}
li {
  display: inline;
}
a {
  display: inline-block;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 2</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 4</a></li>
    <li><a href="#">Menu item 5</a></li>
  </ul>
</div>

Powodem, dla którego mam znacznik a jako inline-block jest to, że nie chcę, aby słowa wewnątrz były również usprawiedliwione, i nie chcę też używać nietłukących spacji.

 12
Author: remitbri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-03 18:48:22

Mam rozwiązanie. Działa w FF, IE6, IE7, Webkit itp.

Przed zamknięciem span.inner Upewnij się, że nie umieszczasz spacji. IE6 się zepsuje.

Możesz opcjonalnie podać .outer szerokość

.outer {
  text-align: justify;
}
.outer span.finish {
  display: inline-block;
  width: 100%;
}
.outer span.inner {
  display: inline-block;
  white-space: nowrap;
}
<div class="outer">
  <span class="inner">THE MENU ITEMS</span>
  <span class="inner">SHOULD BE</span>
  <span class="inner">JUSTIFIED</span>
  <span class="inner">JUST AS</span>
  <span class="inner">PLAIN TEXT</span>
  <span class="inner">WOULD BE</span>
  <span class="finish"></span>
</div>
 8
Author: mikelikespie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-03 18:50:25

Działa z Opera, Firefox, Chrome i IE

ul {
   display: table;
   margin: 1em auto 0;
   padding: 0;
   text-align: center;
   width: 90%;
}

li {
   display: table-cell;
   border: 1px solid black;
   padding: 0 5px;
}
 4
Author: Szajba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-30 15:15:18

Jeszcze jedno rozwiązanie. Nie miałem opcji, aby poradzić sobie z html jak dodawanie distinguished class itp., więc znalazłem czysty sposób css.

Działa w Chrome, Firefox, Safari..Nie wiem o IE.

Test: http://jsfiddle.net/c2crP/1

ul {
  margin: 0; 
  padding: 0; 
  list-style: none; 
  width: 200px; 
  text-align: justify; 
  list-style-type: none;
}
ul > li {
  display: inline; 
  text-align: justify; 
}

/* declaration below will add a whitespace after every li. This is for one line codes where no whitespace (of breaks) are present and the browser wouldn't know where to make a break. */
ul > li:after {
  content: ' '; 
  display: inline;
}

/* notice the 'inline-block'! Otherwise won't work for webkit which puts after pseudo el inside of it's parent instead of after thus shifting also the parent on next line! */
ul > li:last-child:after {
  display: inline-block;
  margin-left: 100%; 
  content: ' ';
}
<ul>
  <li><a href="#">home</a></li>
  <li><a href="#">exposities</a></li>
  <li><a href="#">werk</a></li>
  <li><a href="#">statement</a></li>
  <li><a href="#">contact</a></li>
</ul>
 3
Author: bash2day,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-03 18:52:55

Zrobić <p> z text-align: justify?

Update : Nevermind. To nie działa tak, jak myślałem.

Update 2: Obecnie nie działa w żadnych przeglądarkach innych niż IE, ale CSS3 ma do tego wsparcie w postaci text-align-last

 2
Author: Jordi Bunster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-08 12:14:43

Dla przeglądarek opartych na Gecko, wymyśliłem to rozwiązanie. Chromium, Midori, Epiphany), nadal wyświetlają spację końcową po ostatnim elemencie.

Umieszczam pasek menu w uzasadnionym akapicie . Problem polega na tym, że ostatnia linijka uzasadnionego akapitu nie będzie uzasadniona, z oczywistych powodów. Dlatego dodaję szeroki niewidoczny element (np. img), który gwarantuje, że akapit ma co najmniej dwie linie długa.

Teraz pasek menu jest uzasadniony tym samym algorytmem, którego używa przeglądarka do uzasadniania zwykłego tekstu.

Kod:

<div style="width:500px; background:#eee;">
 <p style="text-align:justify">
  <a href="#">THE&nbsp;MENU&nbsp;ITEMS</a>
  <a href="#">SHOULD&nbsp;BE</a>
  <a href="#">JUSTIFIED</a>
  <a href="#">JUST&nbsp;AS</a>
  <a href="#">PLAIN&nbsp;TEXT</a>
  <a href="#">WOULD&nbsp;BE</a>
  <img src="/Content/Img/stackoverflow-logo-250.png" width="400" height="0"/>
 </p>
 <p>There's an varying number of text-only menu items and the page layout is fluid.</p>
 <p>The first menu item should be left-aligned, the last menu item should be right-aligned. The remaining items should be spread optimal on the menu bar.</p>
 <p>The number is varying,so there's no chance to pre-calculate the optimal widths.</p>
 <p>Note that a TABLE won't work here as well:</p>
 <ul>
  <li>If you center all TDs, the first and the last item aren't aligned correctly.</li>
  <li>If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.</li>
 </ul>
</div>

Uwaga: czy zauważyłeś, że oszukiwałem? Aby dodać element wypełniacza przestrzeni, muszę zgadnąć Szerokość paska menu. Więc to rozwiązanie nie jest całkowicie zgodne z zasadami.

 1
Author: flight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-07 11:02:12

Tekst jest uzasadniony tylko wtedy, gdy zdanie naturalnie powoduje przerwanie linii. Więc wszystko, co musisz zrobić, to naturalnie wymusić przerwanie linii i ukryć to, co jest na drugiej linii: {]}

CSS:

ul {
  text-align: justify;
  width: 400px;
  margin: 0;
  padding: 0;
  height: 1.2em;
  /* forces the height of the ul to one line */
  overflow: hidden;
  /* enforces the single line height */
  list-style-type: none;
  background-color: yellow;
}

ul li {
  display: inline;
}

ul li.break {
  margin-left: 100%;
  /* use e.g. 1000px if your ul has no width */
}

HTML:

<ul>
  <li><a href="/">The</a></li>
  <li><a href="/">quick</a></li>
  <li><a href="/">brown</a></li>
  <li><a href="/">fox</a></li>
  <li class="break">&nbsp;</li>
</ul>

Element li.break musi znajdować się w tej samej linii co ostatni element menu i musi zawierać pewną zawartość (w tym przypadku spację bez łamania), w przeciwnym razie w niektórych przeglądarkach, jeśli nie znajduje się w tej samej linii, zobaczysz małe dodatkowe spacje na końcu linii, a jeśli nie jest to nie zawiera treści, a następnie jest ignorowany, a linia nie jest uzasadniona.

Testowane w IE7, IE8, IE9, Chrome, Firefox 4.

 1
Author: Diaren W,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 00:38:14

If To go with javascript that is possible (this script is base on mootools)

<script type="text/javascript">//<![CDATA[
    window.addEvent('load', function(){
        var mncontainer = $('main-menu');
        var mncw = mncontainer.getSize().size.x;
        var mnul = mncontainer.getFirst();//UL
        var mnuw = mnul.getSize().size.x;
        var wdif = mncw - mnuw;
        var list = mnul.getChildren(); //get all list items
        //get the remained width (which can be positive or negative)
        //and devided by number of list item and also take out the precision
        var liwd = Math.floor(wdif/list.length);
        var selw, mwd=mncw, tliw=0;
        list.each(function(el){
            var elw = el.getSize().size.x;
            if(elw < mwd){ mwd = elw; selw = el;}
            el.setStyle('width', elw+liwd);
            tliw += el.getSize().size.x;
        });
        var rwidth = mncw-tliw;//get the remain width and set it to item which has smallest width
        if(rwidth>0){
            elw = selw.getSize().size.x;
            selw.setStyle('width', elw+rwidth);
        }
    });
    //]]>
</script>

I css

<style type="text/css">
    #main-menu{
        padding-top:41px;
        width:100%;
        overflow:hidden;
        position:relative;
    }
    ul.menu_tab{
        padding-top:1px;
        height:38px;
        clear:left;
        float:left;
        list-style:none;
        margin:0;
        padding:0;
        position:relative;
        left:50%;
        text-align:center;
    }
    ul.menu_tab li{
        display:block;
        float:left;
        list-style:none;
        margin:0;
        padding:0;
        position:relative;
        right:50%;
    }
    ul.menu_tab li.item7{
        margin-right:0;
    }
    ul.menu_tab li a, ul.menu_tab li a:visited{
        display:block;
        color:#006A71;
        font-weight:700;
        text-decoration:none;
        padding:0 0 0 10px;
    }
    ul.menu_tab li a span{
        display:block;
        padding:12px 10px 8px 0;
    }
    ul.menu_tab li.active a, ul.menu_tab li a:hover{
        background:url("../images/bg-menutab.gif") repeat-x left top;
        color:#999999;
    }
    ul.menu_tab li.active a span,ul.menu_tab li.active a.visited span, ul.menu_tab li a:hover span{
        background:url("../images/bg-menutab.gif") repeat-x right top;
        color:#999999;
    }
</style>

I ostatni html

<div id="main-menu">
    <ul class="menu_tab">
        <li class="item1"><a href="#"><span>Home</span></a></li>
        <li class="item2"><a href="#"><span>The Project</span></a></li>
        <li class="item3"><a href="#"><span>About Grants</span></a></li>
        <li class="item4"><a href="#"><span>Partners</span></a></li>
        <li class="item5"><a href="#"><span>Resources</span></a></li>
        <li class="item6"><a href="#"><span>News</span></a></li>
        <li class="item7"><a href="#"><span>Contact</span></a></li>
    </ul>
</div>
 0
Author: Raksmey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-27 06:47:33

Prostsze znaczniki, testowane w Opera, FF, Chrome, IE7, IE8:

<div class="nav">
  <a href="#" class="nav_item">nav item1</a>
  <a href="#" class="nav_item">nav item2</a>
  <a href="#" class="nav_item">nav item3</a>
  <a href="#" class="nav_item">nav item4</a>
  <a href="#" class="nav_item">nav item5</a>
  <a href="#" class="nav_item">nav item6</a>
  <span class="empty"></span>
</div>

I css:

.nav {
  width: 500px;
  height: 1em;
  line-height: 1em;
  text-align: justify;
  overflow: hidden;
  border: 1px dotted gray;
}
.nav_item {
  display: inline-block;
}
.empty {
  display: inline-block;
  width: 100%;
  height: 0;
}

Przykład na żywo .

 0
Author: Litek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 00:35:11

Można to osiągnąć doskonale dzięki dokładnym pomiarom i selektorowi ostatniego dziecka.

ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}
 -1
Author: Jason Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 05:05:20

Wiem, że pierwotne pytanie określa HTML + CSS, ale nie mówi dokładnie Brak javascript ;)

Starając się utrzymać css i znaczniki tak czyste, jak to możliwe, i semantycznie sensowne, jak to możliwe (przy użyciu UL dla menu) wymyśliłem tę sugestię. Prawdopodobnie nie idealny, ale może to być dobry punkt wyjścia: {]}

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

    <head>
        <title>Kind-of-justified horizontal menu</title>

        <style type="text/css">
        ul {
            list-style: none;
            margin: 0;
            padding: 0;
            width: 100%;
        }

        ul li {
            display: block;
            float: left;
            text-align: center;
        }
        </style>

        <script type="text/javascript">
            setMenu = function() {
                var items = document.getElementById("nav").getElementsByTagName("li");
                var newwidth = 100 / items.length;

                for(var i = 0; i < items.length; i++) {
                    items[i].style.width = newwidth + "%";
                }
            }
        </script>

    </head>

    <body>

        <ul id="nav">
            <li><a href="#">first item</a></li>
            <li><a href="#">item</a></li>
            <li><a href="#">item</a></li>
            <li><a href="#">item</a></li>
        <li><a href="#">item</a></li>
            <li><a href="#">last item</a></li>
        </ul>

        <script type="text/javascript">
            setMenu();
        </script>

    </body>

</html>
 -2
Author: David Heggie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-08 13:05:15