如何*真正*证明HTML + CSS中的水平菜单?


86

您可以在HTML的菜单栏上找到很多教程,但是对于这种特定的(尽管是恕我直言)通用案例,我还没有找到任何合适的解决方案:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • 纯文本菜单项数量不一,页面布局也很流畅。
  • 第一个菜单项应左对齐,最后一个菜单项应右对齐。
  • 其余项目应在菜单栏上进行最佳分配。
  • 数字是变化的,因此没有机会预先计算出最佳宽度。

请注意,TABLE在这里也无法正常工作:

  • 如果将所有TD居中,则第一项和最后一项没有正确对齐。
  • 如果左对齐,右对齐第一个。最后一项,间隔将不是最佳的。

没有明显的方法可以使用HTML和CSS干净地实现这一点,这很奇怪吗?

Answers:


43

现代方法-Flexbox

现在CSS3 flexbox具有更好的浏览器支持,我们当中的一些人终于可以开始使用它们了。只需添加其他供应商前缀即可获得更多浏览器覆盖

在这种情况下,只需将父元素设置displayflex,然后将该justify-content属性更改为space-betweenspace-around,以便在子级flexbox项之间或周围添加空间。

使用justify-content: space-between- 此处为示例)

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>


使用justify-content: space-around- (此处为示例)

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>


83

最简单的方法是通过在行的末尾插入一个元素(该元素将占用比剩余的可用空间更多的内容),然后隐藏它来迫使行断开。我已经用一个简单的span元素很容易地做到了这一点:

#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>

#menu span(就我所知)选择器中的所有垃圾都是使大多数浏览器满意所必需的。它应将span元素的宽度强制为100%,这将导致换行,因为根据display: inline-block规则,该元素被视为嵌入式元素。inline-block还可以span实现块级样式规则,例如width,这会导致元素与菜单不匹配,从而使菜单不符合换行规则。

当然,您需要根据span用例和设计调整宽度,但是我希望您了解总体思路并加以调整。


1
如果您使用aspan而不是hr!似乎很有效。这不是真正的工作,HR正在占用可见空间-用于#menu { border: solid 1px green; }确认。另外,display: inline-block;对于不是自然内联元素的元素,在IE(... 7?CompatibilityView?)上也不起作用。HR是一个阻止元素,因此我猜想inline-block不适用于IE上的HR。无论如何,跨度。
ANeves认为SE是邪恶的

9
效果很好,但是如果用&ensp;替换每个空格,结果会更漂亮。(n个空格),以便菜单和项目&1保持紧密靠近。&nbsp; 在Safari中不起作用。
yitwail 2011年

15
我只花了一个多小时就把头撞在墙上,试图弄清为什么这对我不起作用。答案是我需要标签之间有空白。我正在使用WordPress,并且wp_page_menu在每个<li> </ li>之后不包含换行符。使用preg_replace添加了它们,现在可以使用。Fwewww
Greg Perham

1
为了使这些天能够正常工作,您必须在支持它的浏览器中的LI上使用display:inline-block,并使用display:inline并用&nbsp;替换空格。在不支持它的浏览器上。另外,由于ie7不支持内联代码块,因此您必须在force-wrap标签上使用内联代码,并在其中插入足够的&nbsp; s来强制换行。
Joren 2012年

1
为了澄清Joren的意见,UL仍然需要内联,而LI则需要内联。
Moss

12

好的,由于缺乏对:before/的支持,因此该解决方案不适用于IE6 / 7。:after但是:

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>

之所以使用a标记,inline-block是因为我也不希望内部的单词也被证明是合理的,并且我也不想使用不间断的空格。


谢谢!你的灵魂落到了重点。如果我要提出这个问题,我会将其标记为答案。
Andrevinsky

我在将其用于IE中时遇到问题。在Google土地上花了几个小时后,我终于找到了此博客文章:kristinlbradley.wordpress.com/2011/09/15/…最终的窍门是添加text-justify: distribute-all-lines;ul选择器中。似乎是IE专有的东西。
maryisdead 2014年

不知道这是否重要,但我使用的width: 100%不是margin-left: 100%ul:after{content:""; margin-left:100%;}
Eugene Song

8

有解决方案。适用于FF,IE6,IE7,Webkit等

确保关闭之前不要放置任何空格span.inner。IE6会崩溃。

您可以选择提供.outer宽度

.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>


对我而言,此解决方案适用于Gecko,但不适用于WebKit浏览器(已通过Chromium,Midori,Epiphany测试):对于WebKit,最后一项后面有空格。
航班

确保每个跨度之间只有一个空格字符,最后一个内部和结束之间只有两个字符。如果这样不起作用,请在空白处摆弄。Webkit中有一个错误。
mikelikespie 2010年

1
.outer {text-align:justify} .outer span.finish {display:inline-block; width:100%} .outer span.inner {display:inline-block; 空格:nowrap}在IE6和IE7上不起作用。
Binyamin 2010年

.outer line-height: 0力迫使列表的高度被呈现为好像由一行组成。
2014年

4

适用于Opera,Firefox,Chrome和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;
}

1
不幸的是,由于缺少表格单元支持
Philipp Michael

3

另一个解决方案。我没有办法像添加杰出的类等来处理html,所以我找到了一种纯CSS方式。

可在Chrome,Firefox,Safari中使用。..不了解IE。

测试: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>


2

使它成为一个<p>text-align: justify

更新:没关系。就像我想的那样,那根本不起作用。

更新2:目前不适用于IE以外的任何浏览器,但是CSS3以以下形式支持该功能:text-align-last


太快了!我认为我自己的解决方案是独特的,但是您很快就想到了类似的东西。
航班

现在,2016年text-align-last 可以在Safari以外的任何浏览器中使用。这应该是flexbox方法span hack的可能对手。
博多士

1

对于基于Gecko的浏览器,我想出了这个解决方案。尽管此解决方案不适用于WebKit浏览器,但是(例如Chromium,Midori,Epiphany)它们仍在最后一项之后显示尾随空格。

我把菜单栏放在一个合理的段落中。问题是,出于明显的原因,有理由的段落的最后一行不会被证明是有理由的。因此,我添加了一个宽的不可见元素(例如img),以保证该段至少有两行长。

现在,菜单栏由浏览器用于证明纯文本的算法相同。

码:

<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>

备注:你注意到我被骗了吗?要添加空格元素,我必须对菜单栏的宽度进行一些猜测。因此,此解决方案并不完全符合规则。


请注意,如果您在列表项上设置display:inline ...,则在这里也可以使用列表。
Andrew Vit

@安德鲁·维特:你是对的。这也正是asbjornu的解决方案所暗示的。
航班

@flight,如果您认为我的答案是解决方案,可以将其标记为一个吗?目前看来您的问题尚未解决。如果不是,那么很高兴为您提供找到的解决方案或将提供的任何答案标记为您的问题的解决方案。:-)
阿斯比约恩Ulsberg

1

仅当句子自然导致换行时,文本才是合理的。因此,您需要做的就是自然地强制换行,并隐藏第二行中的内容:

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>

li.break元素必须与上一个菜单项在同一行上,并且必须包含一些内容(在这种情况下为不间断空格),否则,在某些浏览器中,如果不在同一行上,则会看到一些小的内容。行末多余的空格,如果其中不包含任何内容,则将其忽略,并且该行不合理。

在IE7,IE8,IE9,Chrome,Firefox 4中进行了测试。


0

是否使用可能的javascript(此脚本基于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>

和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>

和最后的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

标记更简单,已在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>

和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;
}

现场例子


-1

通过一些仔细的测量和最后一个选择器,可以完美地实现这一点。

ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}

4
请记住,文本不会在各处呈现相同的效果,一个像素关闭,您会看到菜单损坏。这仅适用于固定宽度的元素(如图像)。
弗雷坎特(Fregante),2011年

-2

我知道最初的问题指定了HTML + CSS,但没有明确说没有javascript ;)

试图保持css和标记尽可能整洁,并在语义上尽可能地有意义(使用UL作为菜单),我想到了这个建议。可能不理想,但这可能是一个很好的起点:

<!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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.