我正在做一个嵌套的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,以便内部容器在需要时垂直滚动。它并不漂亮,但至少是一种不太破坏可用性的方法。


当前回答

处理:

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

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

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

`

哪里refWrapper是你的你的flex元素

其他回答

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

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

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

我刚刚发现了一个非常棒的纯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。

不幸的是,这么多的主流浏览器在多年后都受到这个错误的困扰。考虑一个Javascript解决方案。每当浏览器窗口调整大小,或者向元素添加内容时,执行这段代码使其调整为适当的宽度。你可以在框架中定义一个指令来为你做这件事。

    element.style.flexBasis = "auto";
    element.style.flexBasis = `${element.scrollWidth}px`;

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

  _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`;

}

可能的JS解决方案..

var ul = $("ul.ul-to-fix");

if(ul.find("li").length>{max_possible_rows)){
    if(!ul.hasClass("width-calculated")){
        ul.width(ul.find("li").eq(0).width()*ul.css("columns"));
        ul.addClass("width-calculated");
     }
}