CSS:使用ul实现固定宽度的水平菜单和可变宽度标签。

11

我有一个水平菜单,其HTML标记如下:

<ul class="menu">
   <li>Item 1</li>
   <li>Longer Item 2</li>
   <li>Item 3</li>
</ul>

后续将实现子菜单和Suckerfish下拉菜单。

ul需要跨越整个页面的宽度(例如100%或1000像素)。

lis的宽度应根据其内容而变化。

因此,结果如下所示:

-----------------100% of page------------
|--Item 1--|--Longer item 2--|--Item 3--|

现在可以通过为每个 li 标签固定宽度来轻松实现,但因为菜单将由CMS驱动,所以我需要允许选项卡的宽度自动变化。使用 表格 将非常简单,但我想不出如何使用 无序列表 实现。

5个回答

31

抱歉,但是Display:Table-Man已于8年前退休(当Edge 12最终开始支持Flexbox时)。

当前最佳解决方案:

.menu {
  display: flex;
  list-style: none;
  padding-left: 0;
  justify-content: space-between; /* if you want the <li>s to be evenly spread
                                     but not expanded, or ... */
}
.menu > li {
  flex-grow: 1; /* ... if you want the <li>s to grow and fill all space */
}

对于移动设备,您可以添加:

.menu {
  flex-wrap: wrap; /* allow items to wrap to a 2nd line, or ... */
}
@media (max-width: 800px) {
  .menu {
    flex-direction: column; /* ... show the items all one under the other */
  }
}

历史性回答:


这是一个编程案例

显示:表格人

ul {
  display: table;
  width: 100%;
}
li {
  display: table-cell;
}

很遗憾,您应该放弃支持IE 6和7的想法,但除此之外,这是正确的方法(或者切换到HTML表格,这可能与标记的语义内容有些远离)。


1
Boldewyn的答案在我的所有测试中都不起作用 - 结果的列表项宽度都相同。 - rda3000
那我建议您展示您的测试(并命名您运行它们的浏览器)。 - Boldewyn
1
table-layout: fixed 会使所有单元格具有相同的宽度。如果您删除该属性,则水平空间将使用100% + 可变项长度(取决于内容)。 - JHannes
JHannes 是完全正确的。table-layout: fixed 这一行应该被删除。非常晚的道歉送给最先发现问题的 rda3000! - Boldewyn

4

这是我的 jQuery 解决方案:

var actualWidth = 1000;
var totalLIWidth = 0;

// Calculate total width of list items
var lis = $('ul li');

lis.each(function(){
    totalLIWidth += $(this).width();
});

// Work out how much padding we need
var requiredPadding = Math.round(((actualWidth-totalLIWidth)/lis.length)/2);

// To account for rounding errors, the error is going to be forced into the first tab.
var roundingErrorFix = (requiredPadding*lis.length*2)+totalLIWidth-actualWidth;

// Apply padding to list items
lis.each(function(i) {
    if(i==0) {
        $(this).css('padding-left',requiredPadding-roundingErrorFix+'px')
            .css('padding-right',requiredPadding-roundingErrorFix+'px');
    }
    else {
        $(this).css('padding-left',requiredPadding+'px')
            .css('padding-right',requiredPadding+'px');
    }
});

好的解决方案,但是只有在将“roundingErrorFix”除以2后再应用于第一个项目后,它才对我起作用。 - Matthew Rapati
很好的回答 - 需要注意的一点是列表项的宽度不包括边框,因此需要在第10行(lis.each循环后)将边框添加到totalLIWidth中。 - Shadi Almosri

3
如果您熟练使用JavaScript,jQuery可以通过以下方式解决此问题。
var $menu, totalwidth;

$menu = $('ul.menu');
totalwidth = ($menu.width()/100);

$('ul.menu li').each(function(){
    this.css('width',String(Math.floor(this.width()/totalwidth))+'%');
});

$menu.css('width','100%');

这还未经过测试,但在我看来是正确的。如果您有任何问题,请评论。


显式字符串转换是不必要的,但除此之外,你比我更快 ;) - Justin Johnson
这可能比想象中更棘手:$menu.width() 默认情况下将是100%(尽管您实际获得的值将以像素为单位),除非您浮动UL,因为UL是块元素。因此,您必须先浮动再取消浮动UL,以便获取totalwidth的正确值。或者,您可以首先汇总LI元素的宽度,然后再次浏览它们以调整到新的宽度来获取totalwidth。 - wheresrhys
那是我的第一个想法,但我不想做两个循环... 浮点和非浮点听起来像是一个安全的选择,我应该编辑我的代码吗? - Gausie
谢谢 - 是的,这是一个起点,但它还必须更复杂才能解决舍入误差的问题。我的答案太丑了,不好意思! - cbp
这也会产生一种不太美观的结果 - 填充会按比例调整到项目的宽度。实际上,我们想要固定大小的填充 - 我将在下面回答。 - cbp

1

我认为boldewyn的建议应该可行。我会在现代浏览器中使用这种方法,然后使用条件注释将以下内容提供给ie6/7,以便在那里看起来不错,尽管它不会跨越100%的宽度。

ul {
  width: 100%;
}
li {
  float:left; // or display:inline-block;
}

-1
如果您想要样式化ul(使其跨越整个页面),最好的方法是将其包装在一个div中,样式化该div,然后允许ul根据其内容自动伸展。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接