绝对定位的flexbox不能自适应内容大小

24

如下代码段所示(在Fiddle中查看),一个绝对定位的、列式的flexbox无法扩展到适应其子元素。

例如,在Chrome中,它只能作为最宽的子元素和最短列的高度。

有没有人可以建议一种解决方案,而不使用任何额外的标记?

编辑:列表中的项目数量将是动态的,每个项目中的文本也将是动态的。我需要在一组项目后换到新的一列。

*{box-sizing:border-box;}
ul{
    background:#090;
    display:flex;
    flex-flow:column wrap;
    left:0;
    list-style:none;
    max-height:202px;
    padding:5px;
    position:absolute;
    top:0;
}
li{
    background:rgba(255,0,0,.75);
    color:#fff;
    flex:1 0 30px;
    font-family:arial;
    line-height:30px;
    max-height:30px;
    margin:1px;
    padding:0 2px;
    min-width:100px;
}
<ul>
    <li>Line 0</li>
    <li>Line 1</li>
    <li>Line 2</li>
    <li>Line 3</li>
    <li>Line 4</li>
    <li>Line 5</li>
    <li>Line 6</li>
    <li>Line 7</li>
    <li>Line 8 is a little bit longer</li>
</ul>


你需要这些数据分别在两列中吗? - lharby
你能详细阐述一下吗,lharby? - Shaggy
抱歉,我对flex属性并不是很了解。我尝试将其设置为clearfix的默认属性,并提供display:block的备用方案,以便旧浏览器可以解释它。我想你可以让li浮动起来,然后给它们50%、33%、25%等宽度,但我认为这违背了使用flex属性的初衷。 - lharby
你遇到的问题与绝对定位无关,而是Flexbox中的缺陷。正如您在此fiddle中所看到的... https://jsfiddle.net/tctfav4c/ ...如果更改为inline-flex,它仍然表现相同。我将其标记为重复,并让我知道您是否认为这样做不好。 - Asons
@LGSon,通常把较新的问题关闭为重复旧问题吗? - Shaggy
显示剩余5条评论
2个回答

10
使用position:absolute;的弹性盒不再被视为弹性盒,因此会出现您当前的问题。如果您要使用position:absolute;,则必须使用预定义的宽度和高度。请参阅w3c关于Flexbox的文档。通过切换到position:absolute;,您会强制弹性容器成为块级元素(这对所有具有position:absolute;的元素都会发生),从而消除其灵活性,并且因为其内容不是块元素而是弹性子项,它们只能影响弹性级别容器而不是块级容器。
Jquery解决方案:可以使用jquery来实现此目的,但这不是纯CSS的解决方案。获取容器的原始宽度,然后获取每个第6个元素的最大宽度(因为这时您的行会断开以形成新列),然后计算总列数并用它乘以每列的最大宽度,最后将其全部加起来以获得所需的容器宽度。随意添加或删除新列以进行测试。可参考示例
var count = $("ul.flex-container li:nth-child(6n)").length;

var firstWidth = Math.max.apply(null, $("ul.flex-container").map(function() {
  return $(this).outerWidth(true);
}).get());

var childWidth = Math.max.apply(null, $("ul.flex-container li:nth-child(6n+6)").map(function() {
  return $(this).outerWidth(true);
}).get());

var totalWidth = childWidth * count

$("ul.flex-container").css({
  width: firstWidth + totalWidth,
});
ul.flex-container {
  background: #090;
  display: flex;
  flex-flow: column wrap;
  list-style: none;
  max-height: 192px;
  padding: 5px;
  position: absolute;
}
ul.flex-container li {
  background: rgba(255, 0, 0, .75);
  color: #fff;
  flex: 1 0 30px;
  font-family: arial;
  line-height: 30px;
  margin: 1px;
  padding: 0 2px;
  min-width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul class="flex-container">
  <li>Line 0</li>
  <li>Line 1</li>
  <li>Line 2</li>
  <li>Line 3</li>
  <li>Line 4</li>
  <li>Line 5</li>
  <li>Line 6</li>
  <li>Line 7</li>
  <li>Line 8 is a little bit longer</li>
  <li>Line 0</li>
  <li>Line 1</li>
  <li>Line 2</li>
  <li>Line 3</li>
  <li>Line 4</li>
  <li>Line 5</li>
  <li>Line 6</li>
  <li>Line 7</li>
  <li>Line 8 is a little bit longer</li>
</ul>


谢谢,DCdaz。我再看了一下那个文档,虽然它指出“弹性容器的绝对定位子元素不参与弹性布局”,但我没有看到关于绝对定位的弹性容器的任何提及。 - Shaggy
嗨Shaggy,最好通读一遍以了解其要点,这是一个关键领域。 "flex items themselves are flex-level boxes, not block-level boxes: they participate in their container’s flex formatting context, not in a block formatting context." 通过更改为绝对定位,您可以强制将flex容器变为块元素,从而消除其灵活性,并且反过来,其内容不是块元素,而是只能影响flex级容器而不是块级容器的flex子元素。 - user4563161
你应该将这个加入到你的回答中 :) - Shaggy
目前已点赞。如果在接下来的一两天里没有人提供解决方案,我会接受这个答案,因为它解释了问题发生的原因。不过,我不确定能否授予悬赏,因为你的答案并没有包含我真正想要的解决方案。 - Shaggy
这是一个完全可用的版本,可以满足您的需求,但它使用了jQuery。 - user4563161
我现在会接受这个作为一个解决问题的工作方案,但很遗憾它并没有提供我正在寻找的解决方案,所以我恐怕不能授予您赏金。 - Shaggy

0

你的子元素无法适应弹性容器的原因是你在容器上设置了max-height

但是,在你的原始示例中发生的情况很奇怪(特别是子元素从列中解除堆叠);

看起来弹性项无法识别容器边框,而弹性盒子仍然试图将它们塞进去(甚至更改flex-direction:column);
唯一有意义的是最宽元素的最大宽度。

这里是一个没有最大宽度的片段:

ul{
    background:#090;
    display:flex;
    flex-flow:column wrap;
    list-style:none;
    padding:5px;
    position:absolute; /*max-height:192px;*/
}
/*ul::after{display:table;clear:both; content:''}clearfix*/
li{
    background:rgba(255,0,0,.75);
    color:#fff;
    flex:1 0 30px;
    font-family:arial;
    line-height:30px;
    margin:1px;
    padding:0 2px;
    min-width:100px;
}
<ul>
    <li>Line 0</li>
    <li>Line 1</li>
    <li>Line 2</li>
    <li>Line 3</li>
    <li>Line 4</li>
    <li>Line 5</li>
    <li>Line 6</li>
    <li>Line 7</li>
    <li>Line 8 is a little bit longer</li>
</ul>

编辑

我不知道你想要的输出是什么,但一个典型的flexbox实现可能是这样的:

ul{
    background:#090;
    display:flex;
    flex-flow:column wrap;
    list-style:none;
    padding:5px;
    /*position:absolute;*/
    height:192px;
}
   /*ul::after{display:table;clear:both; content:''}/*clearfix*/
li{
    background:rgba(255,0,0,.75);
    color:#fff;
    flex:1 0 30px;
    font-family:arial;
    line-height:30px;
    margin:1px;
    padding:0 2px;
   /* width:100px;*/
}
<ul>
    <li>Line 0</li>
    <li>Line 1</li>
    <li>Line 2</li>
    <li>Line 3</li>
    <li>Line 4</li>
    <li>Line 5</li>
    <li>Line 6</li>
    <li>Line 7</li>
    <li>Line 8 is a little bit longer</li>
</ul>


这并没有以任何方式回答我的问题,它只是基本上重复了我所说的话。 - Shaggy
删除 max-height 不解决你的问题吗?这段代码片段看起来没问题。 - maioman
不,它不会。当达到该“max-height”时,我想要换到一个新列。 - Shaggy
flex-flow 属性是 flex-directionflex-wrap 的缩写,因此在您的情况下,flex-direction 的值为 column,预期的行为是垂直扩展,而 max-height 正在破坏 flexbox。 - maioman
它在垂直方向上扩展并在必要/可能的情况下换行,因此需要使用 flex-wrap 属性。max-height 属性不是问题所在,它导致子元素按照我想要的方式布局。问题出在父元素没有按预期行事。 - Shaggy

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