How to Make a Flexbox Container That Stretches to Fit Wrapped Items

How can I make a flexbox container that stretches to fit wrapped items?

"Solution"

I use the term solution lightly as this is insanely difficult to do without fixed rows like Tomas suggested (i.e. without altering the HTML to a more conventional style), or generally without some high degree of hacking. Furthermore, the height halves unless there are 2 rows completed and the containing div cannot be reduced in size reliably; comment out child 7 and see what happens. Then when you also uncomment 8 see that it goes back to 'normal'.

I have been messing around for an hour or so and the best I can come up with is in this fiddle.


I'd like to offer a little background

The default flex-flow is row nowrap, this sets a certain width x on the element lucky enough to receive that rule. It appears that in this case changing the flex-flow to column does not reset the width x defined on that element. The element takes the width x as if it were flex-flow: row nowrap (try this for yourself).

There's a whole heap of width inheritance issues that stem from this, we cannot set the flex-basis property (it's not meant to behave like this I believe) so we need to wrap everything in another element .container which we can define width on, and put the actual column styles on a .row element instead. However, .container will not shrink either. At best we have our column properly defined in width with the .container(ing) element for both doing it's own thing.

Thus we require a pseudo element ::after to provide the background with correct width, including some margin and calc() hacks to simulate padding.

I could type a lot more but I don't think this is a viable solution at all, really just a 'proof' of how it cannot be done nicely.

If you wanted to add more rows you'd have to change the width from 50% for 2 (1/2), to 33% for 3 (1/3) etc... it's not really as scaleable as editing the HTML itself.

So to conclude, there's a working demo for 2 rows only but for now this doesn't seem plausible with that current HTML markup structure.

CSS flex-wrap how to make the height do not stretch

The default direction of flex is row, and when you use flex-wrap: wrap push overflowed element downed to another row, and the row height will default always equal to the highest element of that row, that why you seeing the element having that gap.

This can be done if you change the flex direction to column and give the wrap element a fixed height so it push overflowed element to it right, from top to bottom.

.wrap {  /*Added these*/  height: 300px;  flex-direction: column;  /*-----------*/  display: flex;  align-items: baseline;  align-content: space-around;  flex-wrap: wrap;   background-color: lightblue;
}
.box { display: flex; background-color: tomato; box-sizing: border-box; border: 1px solid #C4C4C4; height: 100px; width: 45%; margin-top: 15px;}
.box1, .box5 { height: 20px;}
  <div class="wrap">    <div class="box box1">box1</div>    <div class="box box2">box2</div>    <div class="box box3">box3</div>    <div class="box box4">box4</div>    <div class="box box5">box5</div>    <div class="box box6">box6</div>  </div>

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

How can I make a display:flex container expand horizontally with its wrapped contents?

It seems this issue cannot be solved only with CSS, so I propose you a JQuery solution

container width = position of the last child - position of the container + width of the last child (including margin)

Code :

$(document).ready(function() {
$('.container').each(function( index ) {
var lastChild = $(this).children().last();
var newWidth = lastChild.position().left - $(this).position().left + lastChild.outerWidth(true);
$(this).width(newWidth);
})
});

Demo :

http://jsfiddle.net/qzea320L/

Fill the remaining height or width in a flex container

Use the flex-grow property to make a flex item consume free space on the main axis.

This property will expand the item as much as possible, adjusting the length to dynamic environments, such as screen re-sizing or the addition / removal of other items.

A common example is flex-grow: 1 or, using the shorthand property, flex: 1.

Hence, instead of width: 96% on your div, use flex: 1.


You wrote:

So at the moment, it's set to 96% which looks OK until you really squash the screen - then the right hand div gets a bit starved of the space it needs.

The squashing of the fixed-width div is related to another flex property: flex-shrink

By default, flex items are set to flex-shrink: 1 which enables them to shrink in order to prevent overflow of the container.

To disable this feature use flex-shrink: 0.

For more details see The flex-shrink factor section in the answer here:

  • What are the differences between flex-basis and width?

Learn more about flex alignment along the main axis here:

  • In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?

Learn more about flex alignment along the cross axis here:

  • How does flex-wrap work with align-self, align-items and align-content?

Flexbox contents don't stretch to fit container, despite not having their heights set anywhere

We can set display: flex; flex-direction:column; height: 100vh; to the row class and set flex: 1 for the element that needs to fill the remaining space. In addition, try to set flex-direction: column for the flex container:

html, body, .container-fluid, .row, #left-panel {
display: flex;
flex-direction: column;
height: 100vh;
}

.thumbnail-view {
margin: 2px;
padding: 2px;
width: 100%;
overflow-y: scroll;
background-color: lightpink;
flex: 1;
}

.buttons-placeholder {
padding-right: 15px;
padding-left: 15px;
display: flex;
justify-content: center;
flex-flow: row wrap;
}

.buttons-placeholder button {
margin: 2px;
flex-grow: 1;
}

.btn-success {
width: 100%;
margin-bottom: 10px;
}

and html:

<div class="container-fluid">
<div class="row">
<div class="buttons-placeholder">
<button type="button" class="btn btn-primary">Load Batch</button>
<button type="button" class="btn btn-primary">Save Batch</button>
</div>
<div class="thumbnail-view"></div>
<button type="button" class="btn btn-success">Submit</button>
</div>
</div>


Related Topics



Leave a reply



Submit