Flex-Flow: Column Wrap. How to Set Container's Width Equal to Content

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

Equal width flex items even after they wrap

Currently, flexbox offers no clean solution for aligning flexible items in the last row or column. It's beyond the scope of the current spec.

Here's more information and various solutions people have used to get around the problem:

  • Targeting flex items on the last row
  • Is it possible for flex items to align tightly to the items above them?

However, last-row alignment is not a problem with another CSS3 technology, Grid Layout. In fact, it's very simple with this method (and requires no changes to the HTML):

.container {  display: grid;  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));  grid-auto-rows: 20px;  grid-gap: 5px;}
.item { background: yellow; text-align: center; border: 1px solid red;}
<div class="container">  <div class="item">1</div>  <div class="item">2</div>  <div class="item">3</div>  <div class="item">4</div>  <div class="item">5</div>  <div class="item">6</div>  <div class="item">7</div>  <div class="item">8</div>  <div class="item">9</div>  <div class="item">10</div></div>

Make flex items have equal width in a row

Flexbox method

In order to make the text items (.section-child) equal width, you need to use flex: 1 1 0, which you have done. This is the same as saying flex: 1.

However, this by itself doesn't achieve the goal for two reasons:

  1. The parent of .section-child, a flex container, but also a flex item in a larger container, is limited to the width of its content, by default. So it won't expand and the text can overflow the container. You need to apply flex: 1 to .section, as well.

  2. A flex item cannot be smaller than the size of its content, by default. The initial setting is min-width: auto. So flex: 1 cannot work to equally distribute container space, because a flex item cannot shrink past the longest item. You need to override this behavior with min-width: 0.

.top-level {  display: flex;  flex-flow: row wrap;}
.section { display: flex; flex-flow: row nowrap; border: 1px solid; margin-right: 12px; margin-top: 12px; flex: 1; min-width: 0;}
.section-child { display: flex; flex-flow: column nowrap; align-items: center; flex: 1; min-width: 0;}
.child-title { white-space: nowrap;}
.vertical-separator { width: 1px; background-color: rgba(0, 0, 0, 0.3); margin: 8px;}
<div class="top-level">  <section class="section">    <div class="section-child">      <h4 class="child-title">Title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Longer title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Much much longer title</h4>      <!--A lot more content here-->    </div>  </section>  <section class="section">    <div class="section-child">      <h4 class="child-title">Title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Longer title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Much much longer title</h4>      <!--A lot more content here-->    </div>  </section>  <section class="section">    <div class="section-child">      <h4 class="child-title">Title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Longer title</h4>      <!--A lot more content here-->    </div>    <div class="vertical-separator"></div>    <div class="section-child">      <h4 class="child-title">Much much longer title</h4>      <!--A lot more content here-->    </div>  </section></div>

Dynamic width flexboxes that wrap yet keep column structure?

You can do this with CSS grid layout, using grid-template-columns. With minmax(200px, 1fr) you can set min-width of each column to 200px and max-width to one track of grid layout. You also need to use auto-fit to make tracks take full width in case there is available space.

.container {  padding: 20px;  display: grid;  background: white;  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));}
.container > div { border: 1px solid black; background: #ececec; margin: 5px; padding: 10px; margin-left: 10px;}
<div class="container">  <div>Div 1</div>  <div>Div 2</div>  <div>Div 3</div>  <div>Div 4</div></div>

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
to writing-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

How to make flex container width adapt to the width (and numbers) of flex items?

You could use a single grid (instead nested flexbox) and set the input on the first row among and before the cards.

here is an example of the idea or a codepen with a side element https://codepen.io/gc-nomade/pen/NWpVeOY :

* {
box-sizing: border-box;
}

.mainContainer {
min-height: 200px;
padding: 1rem;
}

#search {
width: 100%;
height: 2rem;
background-color: var(--Mwhite);
border: 0.05rem solid var(--Mdefault);
border-radius: 0.5rem;
color: var(--Mdefault);
padding: 0 0 0 0.5rem;
outline: 0.05rem solid transparent;
transition: outline 0.5s;
grid-column: 1 / -1;
}

.secondaryContainer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(12.5rem, max-content));
justify-content: center;
row-gap: 1rem;
column-gap: 0.5rem;
}

.card {
background-color: var(--Mwhite);
border: 0.05rem solid var(--Mdefault);
width: 12.5rem;
height: fit-content;
min-height: 16.25rem;
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: space-between;
box-shadow: var(--Mdefault) 0 0 0;
transition: box-shadow 0.5s, border 0.5s;
border-radius: 0.8rem;
}

input#search,
.card {
border: 1px solid black;
;
}
<div class="mainContainer">

<div class="secondaryContainer">
<input type="search" placeholder="search" id="search" />
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
<div class="card">card</div>
</div>
</div>

Flexbox for fixed-height container that wraps items and has dynamic width

You can use grid's autofill property, so you don't need to know the number of columns.

  .my-container {
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(auto-fill, minmax(45px, 1fr));
background-color: rgb(33, 150, 243);
padding: 15px;
height: 600px;
width: fit-content;
}

.my-item {
width: 250px;
height: 25px;
color: white;
padding: 10px;
flex: 0 0 auto;
}

JSFiddle Demo: https://jsfiddle.net/92sak0zc/6/

CSS Flexbox: 3 flex items, 2 Columns (widths equal to content) and 1 item that grows to width

I ended up just adding a container around all of the items except the first one and using flex to make them grow as needed.

Benefits:

  1. The first item can be however long it wants and the other items will grow to match it’s width.
  2. There can be an infinite amount of flex items and the first item will grow to match their combined width.

If anyone does find a method that retains these benefits without adding extra markup, please let us know!

https://codepen.io/albrechtnate/pen/YzzLzLV

.container {  background-color: #ccc;  width: fit-content;}
.container > div:first-child { background-color: blue;}
.container .group { background-color: teal; display: flex;}
.container .group div { background-color: red; flex: 1 0 auto;}
<div class="container">  <div>Item</div>  <div class="group">    <div>Item Two</div>    <div>Item Three</div>  </div></div>
<br>
<div class="container"> <div>Item</div> <div class="group"> <div>Item Two</div> <div>Item Three</div> <div>Item Four</div> <div>Item Five</div> </div></div>
<br>
<div class="container"> <div>Item - This one is super duper extra looper long.</div> <div class="group"> <div>Item Two</div> <div>Item Three</div> </div></div>


Related Topics



Leave a reply



Submit