我正在做一个嵌套的flexbox布局,应该工作如下:

最外层(ul#main)是一个水平列表,当向其中添加更多项时必须向右展开。如果它变得太大,应该有一个水平滚动条。

#main {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    /* ...and more... */
}

这个列表的每一项(ul#main > li)都有一个头部(ul#main > li > h2)和一个内部列表(ul#main > li > ul.tasks)。这个内部列表是垂直的,需要时应该将其包装成列。当包装成更多的列时,它的宽度应该增加,以便为更多的项目腾出空间。这种宽度的增加也适用于外部列表的包含项。

.tasks {
    flex-direction: column;
    flex-wrap: wrap;
    /* ...and more... */
}

我的问题是,当窗口的高度太小时,内部列表不会被包装。我已经尝试过很多次篡改所有的flex属性,试图一丝不差地遵循CSS-Tricks的指导方针,但运气不太好。

这个JSFiddle显示了我目前所拥有的。

预期结果(我想要的):

实际结果(我得到的):

以前的结果(我2015年的结果):

更新

经过一些调查,这开始看起来是一个更大的问题。所有主流浏览器的行为方式都是一样的,这与我的flexbox设计嵌套无关。即使是更简单的flexbox列布局也拒绝在项目换行时增加列表的宽度。

另一个JSFiddle清楚地说明了这个问题。在当前版本的Chrome、Firefox和IE11中,所有项目都能正确换行;列表的高度在行模式下增加,但其宽度在列模式下不增加。同样,在改变列模式的高度时,根本没有元素的立即回流,但行模式中有。

然而,官方规格(具体看例5)似乎表明我想做的事情应该是可能的。

有人能想出解决这个问题的办法吗?

更新2

在多次尝试使用JavaScript在调整大小事件期间更新各种元素的高度和宽度后,我得出的结论是,尝试以这种方式解决它太复杂,太麻烦了。此外,添加JavaScript肯定会破坏flexbox模型,它应该尽可能保持干净。

现在,我回到了overflow-y: auto,而不是flex-wrap: wrap,以便内部容器在需要时垂直滚动。它并不漂亮,但至少是一种不太破坏可用性的方法。


当前回答

我刚刚发现了一个非常棒的纯CSS工作在这里。

https://jsfiddle.net/gcob492x/3/

难点:在列表div中设置写入模式:vertical-lr,然后在列表项中设置写入模式:horizontal-tb。我不得不调整JSFiddle中的样式(删除了很多对齐样式,这对解决方案来说是不必要的)。

注意:评论说它只适用于基于chrome的浏览器,而不是Firefox。我只在Chrome上亲自测试过。有可能有一种方法来修改它,使它在其他浏览器中工作,或者已经有更新到所说的浏览器,使这个工作。

当flexbox项目以列模式换行时,容器的宽度不会增长。通过挖掘这个问题线程,我找到了https://bugs.chromium.org/p/chromium/issues/detail?id=507397#c39,这让我找到了这个JSFiddle。

其他回答

来的晚了,但多年后仍然遇到这个问题。最后找到了一个使用网格的解决方案。在容器上你可以使用

display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);

我在CodePen上有一个在flexbox问题和网格修复之间切换的示例:https://codepen.io/MandeeD/pen/JVLdLd

这个问题

这看起来像是flex布局的一个基本缺陷。

列方向的伸缩容器不会扩展以容纳其他列。(这在flex-direction: row中不是问题。)

这个问题已经被问过很多次了(见下面的列表),在CSS中没有明确的答案。

很难将此定位为一个bug,因为这个问题在所有主要浏览器中都会出现。但它确实提出了一个问题:

怎么可能所有主流浏览器都有flex容器呢 按行方向展开而不是按列方向展开?

你会认为他们中至少有一个人能答对。我只能推测原因。也许它是一个技术上困难的实现,在这次迭代中被搁置了。

更新:该问题似乎在Edge v16中得到解决。


问题说明

OP创建了一个有用的演示来说明这个问题。我复制到这里:http://jsfiddle.net/nwccdwLw/1/


方法选择

来自Stack Overflow社区的hack解决方案:

“看起来这个问题仅靠CSS无法解决,所以我建议您使用JQuery解决方案。” 奇怪的是,大多数浏览器都没有正确地实现列伸缩容器,但对写入模式的支持相当不错。因此,您可以使用具有垂直写入模式的行伸缩容器。”


更多的分析

铬Bug报告 Mark Amery的回答是


其他描述同样问题的帖子

Flex box container width doesn't grow How can I make a display:flex container expand horizontally with its wrapped contents? Flex-flow: column wrap. How to set container's width equal to content? Flexbox flex-flow column wrap bugs in chrome? How do I use "flex-flow: column wrap"? Flex container doesn't expand when contents wrap in a column flex-flow: column wrap, in a flex box causing overflow of parent container Html flexbox container does not expand over wrapped children Flexbox container and overflowing flex children? How can I make a flexbox container that stretches to fit wrapped items? Flex container calculating one column, when there are multiple columns Make container full width with flex Flexbox container resize possible? Flex-Wrap Inside Flex-Grow Flexbox grow to contain Expand flexbox element to its contents? flexbox column stretch to fit content https://stackoverflow.com/q/48406237/3597276 flex-flow: column wrap doesn't stretch the parent element's width Why doesn't my <ul> expand width to cover all the <li>? https://stackoverflow.com/q/55709208/3597276 Flexbox wrap not increasing the width of parent? Absolute Flex container not changing to the correct width with defined max-height

处理:

使用javascript在元素加载到屏幕上后手动设置包装器的宽度并不难。宽度始终是最后一个子元素的右手点。

在react中,我根据添加到flex包装器的任何子包装器的布局更改更新了它,但这可以在任何时候调用,你添加或删除子包装器。

let r = refWrapper.current.lastElementChild.getBoundingClientRect()
refWrapper.current.style.width = (r.x+r.width )+'px'

`

哪里refWrapper是你的你的flex元素

我刚刚发现了一个非常棒的纯CSS工作在这里。

https://jsfiddle.net/gcob492x/3/

难点:在列表div中设置写入模式:vertical-lr,然后在列表项中设置写入模式:horizontal-tb。我不得不调整JSFiddle中的样式(删除了很多对齐样式,这对解决方案来说是不必要的)。

注意:评论说它只适用于基于chrome的浏览器,而不是Firefox。我只在Chrome上亲自测试过。有可能有一种方法来修改它,使它在其他浏览器中工作,或者已经有更新到所说的浏览器,使这个工作。

当flexbox项目以列模式换行时,容器的宽度不会增长。通过挖掘这个问题线程,我找到了https://bugs.chromium.org/p/chromium/issues/detail?id=507397#c39,这让我找到了这个JSFiddle。

我用这种方式解决了我的问题,我希望它能帮助其他偶然发现这个问题的人:

  _ensureWidth(parentElement) {
let totalRealWidth = 0;
let parentElementBoundingRect  = parentElement.getBoundingClientRect()
let lowestLeft = parentElementBoundingRect.x;
let highestRight = parentElementBoundingRect.width;
for (let i = 0; i < parentElement.children.length; i++) {
  let { x, width } = parentElement.children[i].getBoundingClientRect();
  if (x < lowestLeft) {
    lowestLeft = x;
  }
  if (x + width > highestRight) {
    highestRight = x + width;
  }
}
totalRealWidth = highestRight - lowestLeft;
parentElement.style.width = `${totalRealWidth}px`;

}