When Flexbox Items Wrap in Column Mode, Container Does Not Grow Its Width

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

flex-wrap doesn't work for columns when align-items set to any other value than stretched

It's because stretch (which is the default alignment) make the b3 b4 have full height of their parent container which is a needed constraint in order to have a wrapping. Without stretch you will simply have a, overflow since there is no height contraint. Inspect the element in both cases and you will notice that:

  1. With stretch the height is variable based on the parent container which is the screen size
  2. without stretch (when you define align-items: flex-start) the height is fixed based on the content (the 3 boxes inside)

You can get a similar behavior with b1 and b2 if you disable the default shrink effect:

#box-container {
width: 100%;
height: 100vh;
background-color: hsl(0, 0%, 80%);
display: flex;
flex-direction: row;
align-items: flex-start;
/* !!! */
}

.box {
min-width: 135px;
min-height: 135px;
padding: 5px;
display: flex;
flex-wrap: wrap;
/* переносит на следующую строку/столбец элемент, если мало места */
align-content: flex-start;
/* выравнивание рядов по вертикали */
justify-items: flex-start;
/* выравнивание столбцов по горизонтали */
}

#b1 {
background-color: hsl(0, 25%, 50%);
flex-direction: row;
flex-shrink:0;
}

#b2 {
background-color: hsl(90, 25%, 50%);
flex-direction: row-reverse;
flex-shrink:0;
}

#b3 {
background-color: hsl(180, 25%, 50%);
flex-direction: column;
}

#b4 {
background-color: hsl(270, 25%, 50%);
flex-direction: column-reverse;
}

.smallbox {
width: 125px;
height: 125px;
margin: 5px;
display: flex;
align-items: center;
/* выравнивание содержимого по вертикали */
justify-content: center;
/* выравнивание содержимого по горизонтали */
}
<html>

<head>
<title>CSSFlexbox Main Page</title>
<link rel="stylesheet" href="style.css">
</head>

<body style="margin: 0;">
<div id="box-container">
<div id="b1" class="box">
<div class="smallbox sb1" style="background-color:hsla(0, 50%, 50%);">
<h2>1</h2>
</div>
<div class="smallbox sb2" style="background-color:hsla(30, 50%, 50%);">
<h2>2</h2>
</div>
<div class="smallbox sb3" style="background-color:hsla(60, 50%, 50%);">
<h2>3</h2>
</div>
</div>
<div id="b2" class="box">
<div class="smallbox sb1" style="background-color:hsla(90, 50%, 50%);">
<h2>1</h2>
</div>
<div class="smallbox sb2" style="background-color:hsla(120, 50%, 50%);">
<h2>2</h2>
</div>
<div class="smallbox sb3" style="background-color:hsla(150, 50%, 50%);">
<h2>3</h2>
</div>
</div>
<div id="b3" class="box">
<div class="smallbox sb1" style="background-color:hsla(180, 50%, 50%);">
<h2>1</h2>
</div>
<div class="smallbox sb2" style="background-color:hsla(210, 50%, 50%);">
<h2>2</h2>
</div>
<div class="smallbox sb3" style="background-color:hsla(240, 50%, 50%);">
<h2>3</h2>
</div>
</div>
<div id="b4" class="box">
<div class="smallbox sb1" style="background-color:hsla(270, 50%, 50%);">
<h2>1</h2>
</div>
<div class="smallbox sb2" style="background-color:hsla(300, 50%, 50%);">
<h2>2</h2>
</div>
<div class="smallbox sb3" style="background-color:hsla(330, 50%, 50%);">
<h2>3</h2>
</div>
</div>
</div>
</body>

</html>

How to specify when element should wrap with flexbox?

You could use min-width on the blocks. This means they will fully stretch, but when the screen size limits them to being 200px in this example, that breakpoint will lead them to wrap, and their width will never go below 200px.

Another option is to just apply flex-wrap: wrap; on that specific breakpoint you want with a media-query.

For further control, you could also look into flex-basis: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis

EDIT: Responsive image

Genereally it's good to include this line of code on most images: max-width: 100%; height: auto; as this will make images auto-responsive. max-width: 100%; forces the image to never overflow from its container, and height: auto; adjusts the images height so its aspect ratio is correct. Try dragging the screen size and you will see its effect :)