66

Short version

When using flex-flow: column wrap and display: inline-flex, it doesn't shrinkwrap like inline-block:

enter image description here

(function() {
  var ascending = true;
  setInterval(function() {
    var parent = document.getElementById('flex');
    if (ascending) {
      var child = document.createElement('p');
      child.innerHTML = "foo";
      parent.appendChild(child);
    } else {
      parent.removeChild(parent.children[0]);
    }
    if (parent.children.length <= 1) ascending = true;
    if (parent.children.length >= 40) ascending = false;
  }, 20);
})();
(function() {
  var ascending = true;
  setInterval(function() {
    var parent = document.getElementById('failex');
    if (ascending) {
      var child = document.createElement('p');
      child.innerHTML = "foo";
      parent.appendChild(child);
    } else {
      parent.removeChild(parent.children[0]);
    }
    if (parent.children.length <= 1) ascending = true;
    if (parent.children.length >= 40) ascending = false;
  }, 20);
})();
#flexdesc {position: absolute; top: 25px;}
#flex {
  top: 50px;
  position: absolute;
  display: inline-flex;
  flex-flow: row wrap;
  outline: 1px solid black;
  padding: 3px;
  max-height: 100%;
  max-width: 180px;
  align-content: flex-start;
  transform: matrix(0, 1, 1, 0, 0, 0);
  transform-origin: top left;
}

#flex > p {
  margin: 0;
  outline: 1px solid black;
  height: 30px;
  width: 30px;
  align-self: flex-start;
  transform: matrix(0, 1, 1, 0, 0, 0);
}
#failexdesc {position: absolute; top: 275px;}
#failex {
  top: 300px;
  position: absolute;
  display: flex;
  flex-flow: column wrap;
  outline: 1px solid black;
  padding: 3px;
  max-height: 200px;
  align-content: flex-start;
  transform-origin: top left;
}

#failex > p {
  margin: 0;
  outline: 1px solid black;
  height: 30px;
  width: 30px;
  align-self: flex-start;
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <div id="flexdesc">What I expect it to do</div>
  <div id="flex">
    <p>foo</p>
    
    <!-- add extra "<p>foo</p>" here. -->
  </div>
  <div id="failexdesc">What it does</div>
  <div id="failex">
    <p>foo</p>
  </div>
</body>
</html>

Notice how the size of each flex container changes (or doesn't change!)

I want this behavior because I want to place these element side by side for a horizontally scrolling website.

Why doesn't it shrinkwrap? How do I make it shrinkwrap?






Original question

flex-flow: row wrap is simple enough to understand. If nothing is "flexing", it acts similar to inline elements; It flows to the right until it can't do so anymore, at which point it makes a new row.

flex-flow: column wrap with display: flex is similar. It flows down, until it can't flow down anymore (max-width?), and then starts a new column. Of course, since the parent is display: flex, it's a block-level element, so that column will be halfway over due to the fact that align-content defaults to stretch. I could easily change that to flex-start to make the new column adjacent to the previous.

...but the container is still too wide. It's still a block, and fills the width of it's parent.

I need the flexbox to shrink-to-fit its columns. Why? I'm trying to use flexbox in a horizontally scrolling website. Granted, I could just let the children overflow, but that overflowing tends to... break things. So I figured I needed flex-flow: column wrap with display: inline-flex. I was hoping for a "top to bottom, left to right" effect, where the parent has no empty space.

...and then this happened. In chrome, the parent width is equal to the sum of the widths of the children, but otherwise, wrapping is normal. In firefox, the parent is full width, and just grows taller to accomodate the elements (I don't think firefox supports wrapping). In IE11, the width is correct, but the children just overflow down (even out of the body).

I'm so confused.

What am I doing wrong here? I understand that flexbox is a more recent feature, but I can't tell how much of this is my fault vs the browser.

By they way, I'm testing this in chrome. A chrome-only solution is fine by me. (But an elegant catch-all solution is always nice!)


Here's the code for the demo I linked to, in case jsbin is down:

var ascending = true;
   setInterval(function() {
     var parent = document.getElementById('flex');
     if (ascending) {
       var child = document.createElement('p');
       child.innerHTML = "f";
       parent.appendChild(child);
     } else {
       parent.removeChild(parent.children[0]);
     }
     if (parent.children.length <= 1) ascending = true;
     if (parent.children.length >= 30) ascending = false;
   }, 200);
#flex {
  display: inline-flex;
  flex-flow: column wrap;
  outline: 1px solid black;
  padding: 3px;
  max-height: 100%;
  align-content: flex-start;
}
p {
  margin: 0;
  outline: 1px solid black;
  width: 10px;
}
body {
  height: 150px;
  width: 300px;
  outline: 1px dashed black
}
<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8 />
  <title>JS Bin</title>
</head>
<body>
  <div id="flex">
    <p>f</p>
    <!-- add extra "<p>foo</p>" here. -->
  </div>
</body>
</html>
TylerH
  • 20,799
  • 66
  • 75
  • 101
uber5001
  • 3,864
  • 4
  • 23
  • 44
  • IE10 supports prefixed properties from an [older specification](http://www.w3.org/TR/2012/WD-css3-flexbox-20120322/). The problem appears to stem from using inline-flex with the column direction (if you switch to row orientation, it shrinks to fit as you expect). Flexbox is a bit complicated, so you'll need to provide more markup to get a good solution for this. – cimmanon Sep 09 '13 at 13:44
  • This is probably the best resource I have used to gain a better understanding of Flexbox. It probably has an answer for you. http://flexbox.io/ – Andrew Hill Feb 23 '16 at 05:24
  • 2
    This may provide an explanation: http://stackoverflow.com/q/39095473/3597276 – Michael Benjamin Sep 10 '16 at 13:03
  • thanks so match i suffered to arrive this shape – Albaz Sep 27 '17 at 08:29

4 Answers4

14

This was a bug indeed. Here the links to tracker:

https://bugs.chromium.org/p/chromium/issues/detail?id=247963 https://bugs.chromium.org/p/chromium/issues/detail?id=507397

As OP wanted:

I need the flexbox to shrink-to-fit its columns. Why? I'm trying to use flexbox in a horizontally scrolling website. Granted, I could just let the children overflow, but that overflowing tends to... break things. So I figured I needed flex-flow: column wrap with display: inline-flex. I was hoping for a "top to bottom, left to right" effect, where the parent has no empty space.

We can simply achieve it with flex-flow: column wrap;, align-content: flex-start; and a fixed height wrapper together.

http://output.jsbin.com/qixuxiduxe/1

#flex {
  display: flex;
  flex-flow: column wrap;
  max-height: 100%;
  width: 150px;
  overflow: auto;
  align-content: flex-start;
}

p {
  margin: 0;
  align-self: flex-start
}

body {
  height: 150px;
}

Updated fiddle: http://jsbin.com/qixuxiduxe/1/edit?html,css,js,console

Asim K T
  • 16,864
  • 10
  • 77
  • 99
  • It looks like [the bug still exists](https://bugs.chromium.org/p/chromium/issues/detail?id=507397). The container still doesn't have the proper width, whether using `display: flex` or `display: inline-flex`. The width of a `display: flex; flex-flow: column wrap; align-content: flex-start;` remains fixed. I'm on chrome version 54.0.2840.59 (latest stable). Perhaps you are on a newer build where it is fixed? – uber5001 Oct 16 '16 at 17:55
  • You are right. I'm in chrome 53. I think both bug are little different. – Asim K T Oct 17 '16 at 05:13
  • Can this be done without a fixed height and instead a fixed number of columns before wrapping? Using flex-basis: 100% / number leaves the container stretched as if all were on top of each other without wrapping. – Lucent Jun 18 '17 at 06:13
14

If you don't know the height of each item or how many items you will have, a more flexible solution is this:

.parent {
  column-count: 4
}
.child {
  display: inline-block;
  width: 100%;
}

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

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

Asons
  • 84,923
  • 12
  • 110
  • 165
Marcus
  • 3,459
  • 1
  • 26
  • 25
  • 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?](https://meta.stackoverflow.com/questions/317609/is-it-ok-to-copy-paste-myself) – Asons Oct 01 '18 at 18:12
  • Furthermore, if you do think you know a solution that will provide the flow asked for, provide a working code snippet instead of only a CSS fragment. – Asons Oct 01 '18 at 18:16
  • 6
    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. – Marcus Oct 02 '18 at 04:57
  • 2
    @Marcus For what it’s worth, this answer saved me a lot of trouble going down the wrong road for the problem I was trying to solve. – Andrew Patton May 02 '19 at 19:39
  • This solution dramatically decreased the code footprint of what would have been a very complex masonry layout... thank you! – Eliseo D'Annunzio Aug 10 '22 at 05:54
2

I had a similar problem, I had a

div {
    display:flex;
    flex-direction:column;
    flex-wrap:wrap;
}

But child items were not wrapping, it was only one column. The solution was giving the div max-height property then items wrapped.

MaxiGui
  • 6,190
  • 4
  • 16
  • 33
0

It might be late but I think 'column-wrap' is not fully supported by Firefox. As you said, you'll need this in Chrome, in that case you can see what Chris Coyier did: add webkit prefix --> http://css-tricks.com/snippets/css/a-guide-to-flexbox/

Hope is not late :/