Flexbox: wrong width calculation when flex-direction: column, flex-wrap: wrap
This appears to be yet another bug in the Flexible Box Layout Module involving flex-direction: column
and flex-wrap: wrap
.
Browsers seem to be all over the place on this issue.
In this particular case, as stated in a bug report:
It seems to me that the width is calculated as if the inside elements were laid out horizontally (
flex-direction: row
) instead of vertically.
In other cases, the opposite occurs:
- When flexbox items wrap in column mode, container does not grow its width
In both cases, there are currently no flex methods to resolve the problem.
For this particular question, one developer offers a CSS workaround, but I'm not sure it works in all browsers. I wouldn't recommend it unless you're truly desperate:
In some instances, you may be able to workaround this issue by using
vertical writing mode.That is, instead of using
flex-direction: column;
, use
flex-direction: row; writing-mode: vertical-lr;
. Remember to reset
towriting-mode: initial;
in the children of the flexbox.https://bugs.chromium.org/p/chromium/issues/detail?id=507397
Bug reports:
- https://bugs.chromium.org/p/chromium/issues/detail?id=247963
- https://bugs.chromium.org/p/chromium/issues/detail?id=507397
- https://bugzilla.mozilla.org/show_bug.cgi?id=995020
- https://codereview.chromium.org/289903007
- https://src.chromium.org/viewvc/blink?view=revision&revision=178925
When flexbox items wrap in column mode, container does not grow its width
The Problem
This looks like a fundamental deficiency in flex layout.
A flex container in column-direction will not expand to accommodate additional columns. (This is not a problem in flex-direction: row
.)
This question has been asked many times (see list below), with no clean answers in 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?
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.
Illustration of the Problem
The OP created a useful demo illustrating the problem. I'm copying it here: http://jsfiddle.net/nwccdwLw/1/
Workaround Options
Hacky solutions from the Stack Overflow community:
"It seems this issue cannot be solved only with CSS, so I propose you a JQuery solution."
"It's curious that most browsers haven't implemented column flex containers correctly, but the support for writing modes is reasonably good. Therefore, you can use a row flex container with a vertical writing mode."
More Analysis
Chromium Bug Report
Mark Amery's answer
Other Posts Describing the Same Problem
- 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
Make ALL flex-items wrap (like flex-direction: column) when any one flex-item too wide for flex-container
The key insights here are:
1) This problem is a two dimensional problem.
Two dimension problems: solve with display: grid;
One dimension problems: solve with display: flex;
I was thinking as this problem as a single dimension problem because I wanted my radio buttons to be in one case horozontal, and in the other case vertical - both refer to a single dimension. I was wrong because it involves a transition between being vertical and being horozontal, so it is a two dimension problem.
2) grid-auto-flow: column;
I also had to pick an arbitrary view port width to flick from vertical to horozontal, and use a @media statement.
This answer is not perfect, it does not equally size the options when they are not in one horozontal line, but it achieves what I was looking for:
<html>
<head>
<title>Responsive Radio Button</title>
<style type="text/css">
@media(max-width: 600px) {
.resize {
grid-template-columns: 600px;
}
}
@media(min-width: 600px) {
.resize {
grid-auto-flow: column;
grid-auto-columns: 1fr;
}
}
.gridContainer {
display: grid;
/** border so I can see what is going on */
border: 1px dotted lightblue;
}
.gridItem {
/** white-space and min-width stop text wrapping **/
white-space: nowrap;
min-width: max-content;
/** border and margin so I can see what is going on */
border: 1px solid black;
margin: 2px;
}
</style>
</head>
<body>
<div class='gridContainer resize'>
<div class='gridItem'>Medium Length div</div>
<div class='gridItem'>Short div</div>
<div class='gridItem'>Short div</div>
<div class='gridItem'>Short div</div>
<div class='gridItem'>Longest div in this entire html page!</div>
</div>
</div>
</body>
</html>
flex-wrap not working in nested flex container
This may be a bug with a column wrap
flex container. The cyan box is refusing to shrink, which prevents the red box from wrapping.
You could set a width to the second column or .foo2
or .foo3
, and that will force the items to wrap. But that's probably not what you want.
One workaround is to not use column wrap
in this case. Stick to row nowrap
:
.column { display: flex; background: orange; height: 150px;}
.foo,.foo1,.foo3 { display: flex; justify-content: center; color: #333; text-align: center; padding: 1em; background: #ffea61; box-shadow: 0 0 0.5em #999;}
.foo { flex: 1;}
.foo1 { flex: 0 0 200px; background: green;}
.foo2 { display: flex; background: pink; padding: 10px;}
.foo3 { flex-wrap: wrap; margin: 0 auto; background: cyan;}
.bar1,.bar2 { background: blue; width: 50px; height: 30px;}
.bar2 { background: red;}
<div class="column"> <div class="foo1"></div> <div class="foo"> <div class="foo2"> <div class="foo3"> <div class="bar1"></div> <div class="bar2"></div> </div> </div> </div> <div class="foo1"></div></div>
flex-flow: column wrap doesn't stretch the parent element's width
You are trying to have a flex container inside the oder one, the first one needs the display flex to get the content of the element below
I would also make some small changes but it really depends on what you are trying to achive.
If this isnt what you were looking for, please comment so i can try to improve it.
Hope this works :)
.box{
background: #f03;
position: relative;
display: flex;
max-width: 220px;
padding: 20px;
}
.in{
display: flex;
flex-wrap: wrap;
max-width: 220px;
}
*{ margin: 0; padding: 0; } .box{ background: #f03; position: relative; display: flex; max-width: 220px; padding: 20px; } .in{ display: flex; flex-wrap: wrap; max-width: 220px; } .item{ background: #fe3; width: 100px; margin-bottom: 20px; height: 100px; } .item-2{ order: 3; } .item-3{ margin-left: 20px; }
<body> <div class="box"> <div class="in"> <div class="item">1</div> <div class="item item-2">2</div> <div class="item item-3">3</div> </div> </div> </body> <!-- 第三个并没有把父元素宽度撑开 -->
Better way to set distance between flexbox items
- Flexbox doesn't have collapsing margins.
- Flexbox doesn't have anything akin to
border-spacing
for tables (edit: CSS propertygap
fulfills this role in newer browsers, Can I use)
Therefore achieving what you are asking for is a bit more difficult.
In my experience, the "cleanest" way that doesn't use :first-child
/:last-child
and works without any modification on flex-wrap:wrap
is to set padding:5px
on the container and margin:5px
on the children. That will produce a 10px
gap between each child and between each child and their parent.
Demo
.upper {
margin: 30px;
display: flex;
flex-direction: row;
width: 300px;
height: 80px;
border: 1px red solid;
padding: 5px; /* this */
}
.upper > div {
flex: 1 1 auto;
border: 1px red solid;
text-align: center;
margin: 5px; /* and that, will result in a 10px gap */
}
.upper.mc /* multicol test */ {
flex-direction: column;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
<div class="upper">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
<div class="upper mc">
<div>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa<br/>aaa</div>
<div>aaa<br/>aaa<br/>aaa</div>
<div>aaa</div>
<div>aaa</div>
</div>
flexbox column wrap list without overlapping items
Using flexbox with column wrap
is notorious for bugs (see a partial list below).
There are so many problems with this set up, that I would recommend staying away from column wrap
whenever possible. Use row wrap
or CSS Grid instead.
In this particular case, the columns are wrapping the content properly, but the flex algorithm is not factoring in the width needed to accommodate the list item markers.
To illustrate, here's the content with a surrounding border:
.modal { width: 600px;}
.wrapped-list { margin-top: 12px; max-height: 200px; display: flex; flex-direction: column; flex-wrap: wrap;}
li { border: 1px solid red;}
<div class="modal"><ol class="wrapped-list"><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li><li>Student Name</li></ol></div>
Related Topics
How to HTML Encode/Escape a String? Is There a Built-In
How to Get a Web Page Header/Footer Printed on Every Page
CSS Custom Cursor Doesn't Work in Ff/Chrome
How to Disable Form Fields Using CSS
What Was the <Xmp> Tag Used For
Use HTML5 (Datalist) Autocomplete with 'Contains' Approach, Not Just 'Starts With'
CSS for Changing Color of Last Word in H1
Equalize the Height of Left and Right Div, Prevent Right Div from Going Below Left Div
How to Show Disable HTML Select Option in by Default
HTML Favicon.Ico Won't Show on Google Chrome
How to Get a Background Image to Print Using CSS
HTML Video Player Plays Sound But Not Video
Why Are Dashes Preferred for CSS Selectors/HTML Attributes
Html-Tooltip Position Relative to Mouse Pointer
What Values for Checked and Selected Are False