【问题标题】:How do I *really* justify a horizontal menu in HTML+CSS?我如何*真正*证明 HTML+CSS 中的水平菜单?
【发布时间】:2010-09-08 03:37:21
【问题描述】:

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

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • 纯文本菜单项数量不等,页面布局流畅。
  • 第一个菜单项应左对齐,最后一个菜单项应右对齐。
  • 其余项目应以最佳方式分布在菜单栏上。
  • 数量不同,因此无法预先计算出最佳宽度。

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

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

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

【问题讨论】:

    标签: html css


    【解决方案1】:

    另一种解决方案。我没有选择像添加区分类等处理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】:

      找到了解决办法。适用于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 有一个 bug。
      • .outer {text-align: justify} .outer span.finish {display: inline-block;宽度:100%} .outer span.inner {display: inline-block; white-space: nowrap} 不适用于 IE6 和 IE7。
      • 给出.outer line-height: 0 强制列表的高度呈现为好像它由一行组成。
      【解决方案3】:

      好的,这个解决方案在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是因为我不希望里面的单词也被证明是合理的,我也不想使用不间断的空格。

      【讨论】:

      • 谢谢!你的灵魂是关键。如果我要提出问题,我会将其标记为答案。
      • 我无法让它在 IE 中运行。在谷歌的土地上呆了几个小时后,我终于找到了这篇博文:kristinlbradley.wordpress.com/2011/09/15/… 最后的诀窍是将text-justify: distribute-all-lines; 添加到ul 选择器中。似乎是专有的 IE 东西。
      • 不确定这是否重要,但我使用了width: 100% 而不是margin-left: 100%ul:after{content:""; margin-left:100%;}
      【解决方案4】:

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

      【讨论】:

      • 如果您使用span 而不是hr,它似乎可以工作! 这不是真的有效,HR 占用了可见空间 - 使用 #menu { border: solid 1px green; } 来确认。此外,display: inline-block; 不适用于 IE(...7?CompatibilityView?)对于不是自然内联元素的元素。 HR 是一个块元素,所以我猜 inline-block 不适用于 IE 上的 HR。无论如何,跨度。
      • 效果很好,但是如果你用   替换每个空格,结果会更漂亮。 (n 个空格),以便 Menu & item & 1 靠得很近。  在 Safari 中不起作用。
      • 我花了一个多小时将头撞在墙上,试图弄清楚为什么这对我不起作用。答案是我需要标签之间的空白。我在 WordPress 中工作,并且 wp_page_menu 不包括每个
      • 之后的换行符。使用 preg_replace 添加它们,现在可以使用。 Fwewww
    • 为了让这个工作这些天你必须在支持它的浏览器中的 LI 上使用 display: inline-block,并使用 display: inline with space 替换为  在不支持它的浏览器上。此外,由于 ie7 不支持 inline-block,因此您必须在 force-wrap 标记上使用 inline 并在其中插入足够多的  s 以强制换行。
    • 为了澄清Joren的评论,UL仍然需要内联并且LI的内联块。
    • 【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

        Live example.

        【讨论】:

          【解决方案7】:

          现代方法 - Flexboxes!

          现在CSS3 flexboxes 拥有better browser support,我们中的一些人终于可以开始使用它们了。只需为 more browser coverage 添加额外的供应商前缀。

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

          使用justify-content: space-between - (example here)

          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>

          【讨论】:

            【解决方案8】:

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

            【讨论】:

            【解决方案9】:

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

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

            【讨论】:

            • 请记住,文本不会在任何地方呈现相同的,一个像素关闭,您会看到一个损坏的菜单。这仅适用于像图像这样的固定宽度元素。
            【解决方案10】:

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

            【讨论】:

              【解决方案11】:

              对于基于 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,如果您认为我的回答是一个解决方案,您可以将其标记为一个吗?现在看来你的问题没有解决。如果不是,如果您向我们提供您找到的解决方案或将提供的任何答案标记为您的问题的解决方案,那就太好了。 :-)
              【解决方案12】:

              我知道原来的问题指定了 HTML + CSS,但没有具体说 no 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>
              

              【讨论】:

                【解决方案13】:

                使用text-align: justify 将其设为&lt;p&gt;

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

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

                【讨论】:

                猜你喜欢
                相关资源
                最近更新 更多
                热门标签