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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 22:12:52  来源:igfitidea点击:

How do I *really* justify a horizontal menu in HTML+CSS?

htmlcss

提问by flight

You find plenty of tutorials on menu bars in HTML, but for this specific (though IMHO generic) case, I haven't found any decent solution:

您可以在 HTML 中的菜单栏上找到大量教程,但是对于这个特定的(尽管恕我直言)案例,我还没有找到任何像样的解决方案:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • There's an varying number of text-only menu items and the page layout is fluid.
  • The first menu item should be left-aligned, the last menu item should be right-aligned.
  • The remaining items should be spread optimally on the menu bar.
  • The number is varying,so there's no chance to pre-calculate the optimal widths.
  • 纯文本菜单项的数量各不相同,页面布局也很流畅。
  • 第一个菜单项应左对齐,最后一个菜单项应右对齐。
  • 其余项目应在菜单栏上以最佳方式展开。
  • 数字是变化的,所以没有机会预先计算最佳宽度。

Note that a TABLE won't work here as well:

请注意, TABLE 在这里也不起作用:

  • If you center all TDs, the first and the last item aren't aligned correctly.
  • If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.
  • 如果将所有 TD 居中,则第一项和最后一项未正确对齐。
  • 如果左对齐和右对齐第一个响应。最后一项,间距将是次优的。

Isn't it strange that there is no obvious way to implement this in a clean way by using HTML and CSS?

没有明显的方法可以通过使用 HTML 和 CSS 以干净的方式实现这一点,这难道不奇怪吗?

采纳答案by Josh Crozier

Modern Approach - Flexboxes!

现代方法 -弹性盒

Now that CSS3 flexboxeshave better browser support, some of us can finally start using them. Just add additional vendor prefixes for more browser coverage.

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

In this instance, you would just set the parent element's displayto flexand then change the justify-contentpropertyto either space-betweenor space-aroundin order to add space between or around the children flexbox items.

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

Using justify-content: space-between- (example here):

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



Using justify-content: space-around- (example here):

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

回答by Asbj?rn Ulsberg

The simplest thing to do is to is to force the line to break by inserting an element at the end of the line that will occupy more than the left available space and then hiding it. I've accomplished this quite easily with a simple spanelement like so:

最简单的做法是通过在行尾插入一个元素,该元素将占据超过剩余可用空间,然后将其隐藏,从而强制该行中断。我用一个简单的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>

All the junk inside the #menu spanselector is (as far as I've found) required to please most browsers. It should force the width of the spanelement to 100%, which should cause a line break since it is considered an inline element due to the display: inline-blockrule. inline-blockalso makes the spanpossible to block-level style rules like widthwhich causes the element to not fit in line with the menu and thus the menu to line-break.

#menu span选择器中的所有垃圾(据我所知)都是为了取悦大多数浏览器。它应该强制span元素的宽度为 100%,这应该会导致换行,因为由于display: inline-block规则它被视为内联元素。inline-block也使span块级样式规则成为可能,例如width导致元素不适合菜单并因此菜单换行。

You of course need to adjust the width of the spanto your use case and design, but I hope you get the general idea and can adapt it.

您当然需要根据span您的用例和设计调整 的宽度,但我希望您了解总体思路并能够适应它。

回答by remitbri

Ok, this solution doesn't work on IE6/7, because of the lack of support of :before/:after, but:

好的,这个解决方案在 IE6/7 上不起作用,因为缺乏:before/的支持: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>

The reason why I have the a tag as an inline-blockis because I don't want the words inside to be justified as well, and I don't want to use non-breaking spaces either.

我将 a 标记作为 aninline-block的原因是因为我不希望里面的单词也被证明是合理的,而且我也不想使用不间断的空格。

回答by mikelikespie

Got a solution. Works in FF, IE6, IE7, Webkit, etc.

得到了解决方案。适用于 FF、IE6、IE7、Webkit 等。

Make sure you don't put any whitespace before closing the span.inner. IE6 will break.

确保在关闭span.inner. IE6 会崩溃。

You can optionally give .outera width

您可以选择提供.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>

回答by Rowinski

Works with Opera , Firefox, Chrome and IE

适用于 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;
}

回答by bash2day

yet another solution. I had no option to tackle the html like adding distinguished class etc., so I found a pure css way.

另一个解决方案。我没有选择像添加尊贵类等来处理 html,所以我找到了一种纯 css 方式。

Works in Chrome, Firefox, Safari..don't know about IE.

适用于 Chrome、Firefox、Safari.. 不了解 IE。

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

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

回答by Jordi Bunster

Make it a <p>with text-align: justify?

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

Update: Nevermind. That doesn't work at all as I'd thought.

更新:没关系。这根本不像我想的那样工作。

Update 2: Doesn't work in any browsers other than IE right now, but CSS3 has support for this in the form of text-align-last

更新 2:现在不能在 IE 以外的任何浏览器中工作,但 CSS3 以text-align-last

回答by flight

For Gecko-based browsers, I came up with this solution. This solution doesn't work with WebKit browsers, though (e.g. Chromium, Midori, Epiphany), they still show trailing space after the last item.

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

I put the menu bar in a justified paragraph. Problem is that the last line of a justified paragraph won't be rendered justified, for obvious reasons. Therefore I add a wide invisible element (e.g. an img) which warrants that the paragraph is at least two lines long.

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

Now the menu bar is justified by the same algorithm the browser uses for justifying plain text.

现在菜单栏的对齐方式与浏览器用于对齐纯文本的算法相同。

Code:

代码:

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

Remark: Do you notice I cheated? To add the space filler element, I have to make some guess about the width of the menu bar. So this solution is not completely down to the rules.

备注:你注意到我作弊了吗?要添加空格填充元素,我必须对菜单栏的宽度进行一些猜测。所以这个解决方案并不完全符合规则。

回答by Diaren W

Text is only justified if the sentence naturally causes a line break. So all you need to do is naturally force a line break, and hide whats on the second line:

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

CSS:

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:

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>

The li.break element must be on the same line as the last menu item and must contain some content (in this case a non breaking space), otherwise in some browsers, if it's not on the same line then you'll see some small extra space on the end of your line, and if it contains no content then it's ignored and the line is not justified.

li.break 元素必须与最后一个菜单项在同一行,并且必须包含一些内容(在这种情况下是一个不间断的空格),否则在某些浏览器中,如果它不在同一行,那么你会看到一些小的行末尾的额外空间,如果它不包含任何内容,则它会被忽略并且该行不合理。

Tested in IE7, IE8, IE9, Chrome, Firefox 4.

在 IE7、IE8、IE9、Chrome、Firefox 4 中测试。

回答by Raksmey

if to go with javascript that is possible (this script is base on mootools)

如果使用 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>

and the css

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

and the last html

和最后一个 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>