繁体   English   中英

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

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

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

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

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

  • 如果将所有 TD 居中,则第一项和最后一项未正确对齐。
  • 如果你左对齐和右对齐第一个resp。 最后的项目,间距将是次优的。

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

最简单的做法是通过在行尾插入一个占用超过剩余可用空间的元素然后隐藏它来强制换行。 我用一个简单的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的宽度,但我希望你能理解并适应它。

现代方法 - 弹性盒

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

在这种情况下,您只需将父元素的display设置为flex ,然后将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 - (example here)

 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>

好的,这个解决方案在 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>

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

得到了解决方案。 适用于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>

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

另一种解决方案。 我无法像添加杰出的类等那样处理 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>

使用text-align: justify使其成为<p>

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

更新 2 :目前在 IE 以外的任何浏览器中都不起作用,但 CSS3 以text-align-last的形式对此提供支持

对于基于 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>

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

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

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 中测试。

更简单的标记,在 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;
}

活生生的例子

是否可以使用 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>

尝试这个

 *{ padding: 0; margin: 0; box-sizing: border-box; } ul { list-style: none; display: flex; align-items: center; justify-content: space-evenly; }
 <ul> <li>List item One</li> <li>List item Two</li> <li>List item Three </li> <li>List item Four</li> </ul>

这可以通过一些仔细的测量和 last-child 选择器完美地实现。

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

我知道最初的问题指定了 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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM