Html 当 flexbox 项目以列模式换行时,容器不会增加其宽度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33891709/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 18:32:51  来源:igfitidea点击:

When flexbox items wrap in column mode, container does not grow its width

htmlcssflexbox

提问by Anders Tornblad

I am working on a nested flexbox layout which should work as follows:

我正在处理嵌套的 flexbox 布局,它应该按如下方式工作:

The outermost level (ul#main) is a horizontal list that must expand to the right when more items are added to it. If it grows too big, there should be a horizontal scroll bar.

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

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

Each item of this list (ul#main?>?li) has a header (ul#main?>?li?>?h2) and an inner list (ul#main?>?li >?ul.tasks). This inner list is vertical and should wrap into columns when needed. When wrapping into more columns, its width should increase to make room for more items. This width increase should apply also to the containing item of the outer list.

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

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

My problem is that the inner lists don't wrap when the height of the window gets too small. I have tried lots of tampering with all the flex properties, trying to follow the guidelines at CSS-Tricksmeticulously, but no luck.

我的问题是当窗口的高度太小时,内部列表不会换行。我已经尝试了大量篡改所有 flex 属性,试图仔细遵循CSS-Tricks的指导方针,但没有运气。

This JSFiddleshows what I have so far.

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

Expected result(what I want):

预期结果(我想要的)

My desired output

我想要的输出

Actual result(what I get):

实际结果(我得到的)

My current output

我的当前输出

Older result(what I got in 2015):

较旧的结果(我在 2015 年得到的)

My older output

我的旧输出

UPDATE

更新

After some investigation, this is beginning to look like a bigger issue. All major browsers behave the same way, and it has nothing to do with my flexbox design being nested. Even simpler flexbox column layouts refuse to increase the list's width when the items wrap.

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

This other JSFiddleclearly demonstrates the problem. In current versions of Chrome, Firefox and IE11, all items wrap correctly; the list's height increases in rowmode, but its width does not increase in columnmode. Also, there is no immediate reflow of elements at all when changing the height of a columnmode, but there is in rowmode.

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

However, the official specs (look specifically at example 5)seem to indicate that what I want to do should be possible.

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

Can someone come up with a workaround to this problem?

有人可以想出解决这个问题的方法吗?

UPDATE 2

更新 2

After a lot of experimenting using JavaScript to update the height and width of various elements during resize events, I have come to the conclusion that it is too complex and too much trouble to try to solve it that way. Also, adding JavaScript definitely breaks the flexbox model, which should be kept as clean as possible.

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

For now, I'm falling back to overflow-y: autoinstead of flex-wrap: wrapso that the inner container scrolls vertically when needed. It is not pretty, but it is one way forward that at least does not break useability too much.

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

回答by Michael Benjamin

The Problem

问题

This looks like a fundamental deficiency in flex layout.

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

A flex container in column-direction will not expand to accommodate additional columns. (This is not a problem in flex-direction: row.)

列方向的 flex 容器不会扩展以容纳额外的列。(这不是问题flex-direction: row。)

This question has been asked many times (see list below), with no clean answers in CSS.

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

It's hard to pin this as a bug because the problem occurs across all major browsers. But it does raise the question:

很难将其视为错误,因为所有主要浏览器都会出现此问题。但它确实提出了一个问题:

How is it possible that all major browsers got the flex container to expand on wrap in row-direction but not in column-direction?

所有主要浏览器怎么可能让 flex 容器在行方向而不是列方向上扩展?

You would think at least one of them would get it right. I can only speculate on the reason. Maybe it was a technically difficult implementation and was shelved for this iteration.

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

UPDATE:The issue appears to be resolved in Edge v16.

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



Illustration of the Problem

问题说明

The OP created a useful demo illustrating the problem. I'm copying it here: http://jsfiddle.net/nwccdwLw/1/

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



Workaround Options

解决方法选项

Hacky solutions from the Stack Overflow community:

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



More Analysis

更多分析



Other Posts Describing the Same Problem

描述相同问题的其他帖子

回答by MandeeD

Late to the party, but was still running into this issue YEARS later. Ended up finding a solution using grid. On the container you can use

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

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

I have an example on CodePen that toggles between the flexbox issue and the grid fix: https://codepen.io/MandeeD/pen/JVLdLd

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

回答by Itay Gal

Since no solution or proper workaround was suggested yet, I managed to obtain the requested behavior with a little different approach. Instead of separating the layout into 3 different divs, I'm adding all the items into 1 div and creating the separation with some more divs in between.

由于尚未提出任何解决方案或适当的解决方法,因此我设法通过稍微不同的方法获得了请求的行为。我没有将布局分成 3 个不同的 div,而是将所有项目添加到 1 个 div 中,并在其间创建更多 div 的分隔。

The proposed solution is hard coded, assuming we have 3 sections, but can be extended to a generic one. The main idea is to explain how we can achieve this layout.

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

  1. Adding all the items into 1 container div that uses flex to wrap the items
  2. The first item of each "inner container" (I'll call it a section) will have a class, which helps us to do some manipulations that create the separation and styling of each section.
  3. Using :beforeon each first item, we can locate the title of each section.
  4. Using spacecreates the gap between the sections
  5. Since the spacewon't cover the full height of the section I'm also adding :afterto the sections so positioning it with absolute position and white background.
  6. To style the background color of each section I'm adding another div inside the first item of each section. I will be position with absolute as well and will have z-index: -1.
  7. To get the correct width of each background, I'm using JS, setting the correct width, and also adding a listener to resize.
  1. 将所有项目添加到 1 个使用 flex 包装项目的容器 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>

回答by user2323336

Possible JS solution..

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