当flexbox项目以列模式包装时,容器的宽度不会增加


166

我正在处理嵌套的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中,所有项目均正确包装;列表的高度在row模式下增加,但其宽度在column模式下不增加。另外,更改column模式高度时,根本没有元素的立即重排,但是处于row模式中。

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

有人可以解决此问题吗?

更新2

经过大量使用JavaScript在调整大小事件期间更新各种元素的高度和宽度的实验之后,我得出的结论是,它太复杂且很难以这种方式解决。另外,添加JavaScript肯定会破坏flexbox模型,该模型应保持尽可能干净。

现在,我回到overflow-y: auto而不是,flex-wrap: wrap以便内部容器在需要时垂直滚动。这不是很漂亮,但是至少不会过多破坏可用性是一种前进的方式。


2
只是一个旁注,但是Chrome中存在一个错误,该错误会导致容器的流程设置为column wrap在包装时不扩大其宽度。有关更多信息,请参见code.google.com/p/chromium/issues/detail?id=247963
Gerrit Bertier 2015年

我也无法在IE11中使用它。在那里,最里面的项目会包装,但是内部列表及其容器(外部项目)不会增加其宽度。目前,我不愿让内部列表滚动,但这不是一个好的长期解决方案,我真的想避免为此添加JavaScript。
Anders Tornblad

Answers:


170

问题

这似乎是挠性布局的根本缺陷。

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

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

很难将其固定为错误,因为该问题发生在所有主要浏览器上。但这确实提出了一个问题:

所有主要的浏览器如何使flex容器在行方向而不是列方向扩展包装?

您可能会认为至少其中之一会做对。我只能推测原因。也许这在技术上很难实现,并且在此迭代中被搁置了​​。

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


问题说明

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


解决方法选项

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


更多分析


描述相同问题的其他帖子


2
根据bug报告的意见,这个问题将不会被固定,直到他们发布他们新的布局引擎LayoutNG
Ben.12

5
您提供并分类的链接数量确实很多。我希望大多数人都这样写答案。好答案。
Vignesh

4
这是一个有用的存储库,列出了一些Flexbox错误及其解决方法:此错误在#14
Ben.12

我们可以使用CSS网格解决此问题吗?
Ismail Farooq

另一个解决方法:codepen.io/_mc2/pen/PoPmJRP从某些方面来说,我发现写模式方法更好
michalczerwinski

37

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

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

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


1
如果我见过一个不错的解决方法!我刚刚进入网格,我喜欢您的解决方案,谢谢您。
艾伯特

发现!解决了我的问题。
Celestin Bochis,

在Chrome中仍然遇到此问题。我希望避免使用网格解决方法。很高兴知道其他人正在使用这种方法!
trukvl19年

救生员。grid-row-end: span X;如果需要某些项目占用更多行,也可以使用。
Meirion Hughes

0

不幸的是,许多主要的浏览器在多年后都遭受了该错误的困扰。考虑使用Javascript解决方法。每当浏览器窗口调整大小或将内容添加到元素时,请执行此代码以将其调整为适当的宽度。您可以在框架中定义一个指令来为您执行。

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

-1

由于尚未提出解决方案或适当的解决方法的建议,因此我设法使用了一些不同的方法来获得请求的行为。我没有将布局分为3个不同的div,而是将所有项目添加到1 div中,并在其中添加了一些div来创建分隔。

假设我们有3个部分,则所提出的解决方案是硬编码的,但是可以扩展为一个通用的部分。主要思想是解释我们如何实现这种布局。

  1. 将所有项目添加到使用flex包裹项目的1个容器div中
  2. 每个“内部容器”的第一项(我将其称为一个部分)将具有一个类,该类有助于我们进行一些操作以创建每个部分的分隔和样式。
  3. 使用:before上的每个第一个项目,我们可以找到每个部分的标题。
  4. 使用space会在各部分之间产生间隙
  5. 由于space不会覆盖整个部分的高度,因此我还要添加:after到这些部分中,以便使用绝对位置和白色背景对其进行定位。
  6. 为了设置每个部分的背景颜色,我在每个部分的第一项中添加了另一个div。我也将拥有绝对的地位z-index: -1
  7. 为了获得每个背景的正确宽度,我使用了JS,设置了正确的宽度,并添加了一个监听器以调整大小。

function calcWidth() {
  var size = $(document).width();
  var end = $(".end").offset().left;

  var todoWidth = $(".doing-first").offset().left;
  $(".bg-todo").css("width", todoWidth);

  var doingWidth = $(".done-first").offset().left - todoWidth;
  $(".bg-doing").css("width", doingWidth);

  var doneWidth = $(".end").offset().left - $(".done-first").offset().left;
  $(".bg-done").css("width", doneWidth + 20);

}

calcWidth();

$(window).resize(function() {
  calcWidth();
});
.container {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  height: 120px;
  align-content: flex-start;
  padding-top: 30px;
  overflow-x: auto;
  overflow-y: hidden;
}

.item {
  width: 200px;
  background-color: #e5e5e5;
  border-radius: 5px;
  height: 20px;
  margin: 5px;
  position: relative;
  box-shadow: 1px 1px 5px 0px rgba(0, 0, 0, 0.75);
  padding: 5px;
}

.space {
  height: 150px;
  width: 10px;
  background-color: #fff;
  margin: 10px;
}

.todo-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "To Do (2)";
  font-weight: bold;
}

.doing-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Doing (5)";
  font-weight: bold;
}

.doing-first:after,
.done-first:after {
  position: absolute;
  top: -35px;
  left: -25px;
  width: 10px;
  height: 180px;
  z-index: 10;
  background-color: #fff;
  content: "";
}

.done-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Done (3)";
  font-weight: bold;
}

.bg-todo {
  position: absolute;
  background-color: #FFEFD3;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -10px;
  z-index: -1;
}

.bg-doing {
  position: absolute;
  background-color: #EFDCFF;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.bg-done {
  position: absolute;
  background-color: #DCFFEE;
  width: 10vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.end {
  height: 150px;
  width: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">

  <div class="item todo-first">
    <div class="bg-todo"></div>
    Drink coffee
  </div>
  <div class="item">Go to work</div>

  <div class="space"></div>

  <div class="item doing-first">
    <div class="bg-doing"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>

  <div class="space"></div>

  <div class="item done-first">
    <div class="bg-done"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>

  <div class="end"></div>

</div>


-2

可能的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");
     }
}

不幸的是,这将无济于事,因为各个元素的高度可能会发生变化。因此元素的数量并不有趣...但是使用columnsstyle属性可能是可行解决方案的起点。也许调整列数 ul的宽度。
Anders Tornblad

1
我还为我一直在研究的React应用程序提供了JS解决方案来解决这个问题。它旨在与任何大小可变的元素一起使用。此处的示例:djskinner.github.io/react-column-wrap。源代码在这里:github.com/djskinner/react-column-wrap
djskinner 17-10-12
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.