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

5

34

When using css flexbox the three main browsers appear to behave entirely differently in certain areas.

In this case I am trying to create a grid of images:

<div class="container">
     <div class="photo"></div>
     <div class="photo"></div>
     <div class="photo"></div>
     <div class="photo"></div>
     <div class="photo"></div>
     <div class="photo"></div>
</div>


.container {
    display:inline-flex;
    flex-flow : column wrap;
    align-content : flex-start;
    height : 100%;
}

In this example I need a container, itself containing several div elements set up to flow from top to bottom and wrapping when they reach the bottom. Ultimately providing me with columns of photos.

However I need the container to expand horizontally to accommodate the wrapped elements:

Here is a quick jsFiddle to demonstrate.

The behaviour is as follows:

  • IE 11 - Correct, the container stretches horizontally to wrap each column of wrapped elements
  • Firefox - The container only wraps the first column of elements, with the rest overflow out.
  • Chrome - The container always stretches to fill the width of its parent, whatever that may be.

In this instance I would like to achieve the behaviour of IE11 in the other two browsers. Therefore my question is, how can I make a flexbox container expand horizontally to match its column wrap contents.

Thanks in advance.

Oregon answered 1/5, 2014 at 13:20 Comment(9)
jsfiddle.net/f7Ku8/4 as i understood you.Diphosgene
you have a row layout distribution with a fixed height container ... that does not make sense; test different layouts hereDelores
@Delores why does that not make sense? I want the container to be a fixed height but expand horizontally as more columns are added. It is a column layout distribution not a row one.Oregon
@Diphosgene Thanks but that isn't what i'm after. Your solution removes flex-box entirely which does indeed make the container expand correctly. However I need the items to flow from the top to bottom in columns, hence the display:inline-flex or display:flex requirement.Oregon
Do you want it to overflow? It's not clear what's your intention. Do you have an example?Delores
@Delores I would like the blue container to expand to fit the column wrapped contents), it does this correctly in IE 11 but does not in Firefox or Chrome. Try my jsFiddle on all three browsers and you will see the difference. IE 11 is the behaviour I would like.Oregon
I dont know how IE behaves ... and you shouldn't rely on it since their flex support is recent... When you set the flex-direction to column you define the Vertical axis as the main axis. In flexbox that means it will fill up the available height and then create a new column.Delores
@Oregon also notice that firefox and chrome have the same behavior when you use display:flex instead of display:inline-flexFender
possible duplicate: https://mcmap.net/q/37568/-when-flexbox-items-wrap-in-column-mode-container-does-not-grow-its-width/3597276Jimmy
S
6

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/

Simonnesimonpure answered 7/10, 2014 at 8:12 Comment(2)
-1. This might work in simple cases, but if there's any potential for the width to change (e.g. due to adding or removing flex items, or changing the height of the flex container) then this is going to break, and if there's no potential for it to change, then why not simply hard-code it in your CSS? Also, this is likely to fail if the flex items have different sizes - you're relying upon the last child being the one whose box extends farthest to the right, but that needn't be true.Defoliate
Writing JS instead of CSS doesn't scale. It works only in simplest cases. -1 for jQuery in 2014.Hydrous
T
59

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. This will swap the block direction with the inline direction, and thus the flex items will flow vertically. Then you only need to restore the horizontal writing mode inside the flex items.

.container {
  display: inline-flex;
  writing-mode: vertical-lr;
  flex-wrap: wrap;
  align-content: flex-start;
  height: 350px;
  background: blue;
}
.photo {
  writing-mode: horizontal-tb;
  width: 150px;
  height: 100px;
  background: red;
  margin: 2px;
}
<div class="container">
  <div class="photo">1</div>
  <div class="photo">2</div>
  <div class="photo">3</div>
  <div class="photo">4</div>
  <div class="photo">5</div>
  <div class="photo">6</div>
  <div class="photo">7</div>
  <div class="photo">8</div>
  <div class="photo">9</div>
</div>

This approach may have its own bugs in edge cases, especially if you mix advanced layout techniques like floats and nested flexboxs. But for most cases it seems to work properly.

Theodicy answered 18/12, 2016 at 14:51 Comment(6)
That's a ridiculous hack. Thanks!Gyatt
This does not seem to work in Firefox. Especially when in nested flexboxes. I believe this is the "Chrome-specific workaround" that @Mark Amery mentions in his answer.Serenata
thanks works in Chrome, FF, Edge... (not IE obviously)Cerebrovascular
incredible that this bug is still out here late 2019.. Anyway, this work-around works great!Ejective
Brilliant, and still relevant in 2022! I did unspeakable things looking for a solution... had I only known of this earlier...Swiss
Hell yeah !! 2023 still rolling. That thing is incredible! :)Outspeak
D
10

The spec says that what you're doing should work, but it's implemented incorrectly in every major browser besides Internet Explorer / Edge, making multi-line inline-flex column layouts useless at present for most developers. Here's a Chromium bug report providing an example that is effectively identical to yours, and noting that it renders incorrectly in Chrome, Safari, and Firefox.

The argument from spec is more complicated than I'm able to understand, but the key point is that Flexible Box Layout Module Level 1 spec defines the intrinsic cross-size of a flex container (that is, the intrinsic height of a flex-direction: row flex container or the intrinsic width of a flex-direction: column flex container) in the section Flex Container Intrinsic Cross Size. There, it is stated:

For a multi-line flex container, the min-content/max-content cross size is the sum of the flex line cross sizes

That is, the intrinsic width of a flex-direction: column flex container should be the sum of the widths of its columns, as you'd expect. (There is more complexity than this, and I don't understand it all, but I believe the above to be broadly true.) However, Chrome, Firefox, and Safari all calculate this width incorrectly; setting width: min-content or width: max-content on a column wrap flex box in Chrome, you can clearly see that the width is set to the width of the widest single element.

A silly Chrome-specific workaround exists, but is probably best avoided. Until the bug is fixed, this part of the Flexbox model simply doesn't work as designed and there's no clean solution available.

Defoliate answered 18/12, 2016 at 14:16 Comment(0)
S
6

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/

Simonnesimonpure answered 7/10, 2014 at 8:12 Comment(2)
-1. This might work in simple cases, but if there's any potential for the width to change (e.g. due to adding or removing flex items, or changing the height of the flex container) then this is going to break, and if there's no potential for it to change, then why not simply hard-code it in your CSS? Also, this is likely to fail if the flex items have different sizes - you're relying upon the last child being the one whose box extends farthest to the right, but that needn't be true.Defoliate
Writing JS instead of CSS doesn't scale. It works only in simplest cases. -1 for jQuery in 2014.Hydrous
D
-1

You have a column layout distribution with a fixed height container.

When you set the flex-direction to column you define the Vertical axis as the main axis.

In flexbox that means it will fill up the available height and then create a new column.

In this JSBIN I use javascript to change the container's height and, because of that, you will see the child items move.

PS: you shouldn't rely on IE behavior since their flex support is recent.

Delores answered 1/5, 2014 at 15:4 Comment(1)
I understand all of this but it doesn't really answer my question I am afraid. I am simply looking for a way to make the flex-box container element automatically expand horizontally to match its contents. If this is not possible then so be it. But it is disappointing since all three browsers behave completely differently in this regard. PS I am not relying on IE's behaviour, that is why I am asking this question. Regardless, thank you for taking the time to answer.Oregon
H
-1

Another possible approach:

.container {
  column-count: 2; /*or whatever */
}
.container > div {
  display: inline-block;
}

https://developer.mozilla.org/en-US/docs/Web/CSS/column-count

You may also need to adjust margin-top of .container > div:first-child if they don't align to the top.

Hus answered 26/9, 2018 at 21:5 Comment(3)
Don't copy/paste the same answer all over, post at one place and then vote to close on the other ... Is it ok to copy/paste myself?Depth
Furthermore, this answer doesn't provide a solution to the asked question, since it will create a different flow than what is asked for.Depth
I'll try to take your rebukes and downvotes to heart. In my defense, I had just spent too much time looking at SO pages about flex, when what I needed was column-count, and I was trying to help others to have a better experience.Hus

© 2022 - 2024 — McMap. All rights reserved.