Flex-Box: Shrink Before Wrap

flex-box: shrink before wrap

Set flex-basis equal to min-width:

.column.stretch {
flex: 1 1 100px; /* or 1 0 100px, and no more need in min-width at all */
max-width: 300px;
min-width: 100px;
background: red;
}

edited JSfiddle example

How to create a flex item that shrinks before it wraps?

The problem is not flex-shrink. The problem is flex-basis. You have it set to 50%.

This means that flex-grow will add free space to the flex-basis, and each item will wrap quickly, before it has an opportunity to shrink.

Switch from flex-basis: 50% to flex-basis: 0.

More specifically, instead of flex: 1 1 50% use flex: 1, which breaks down to this:

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: 0

Now flex-grow distributes free space equally – not proportionally – to both items, and they can shrink before they wrap.

(Here's a more in-depth explanation: Make flex-grow expand items based on their original size)

.m {  display: flex;  flex-wrap: wrap;}
.l_1 { background-color: red; flex: 1;}
.r_1 { background-color: yellow; flex: 1;}
<div class=m>  <div class=l_1>left_______________________________________________X</div>  <div class=r_1>right</div></div>

Is there any use for flex-shrink when flex-wrap is wrap?

Meanwhile, if flex-wrap is set to wrap, there can't be any negative space, can it?

If an element is wider than the flex container, it can't wrap across multiple lines, but it can shrink.

Therefor this property is just useless, or at least I can see any effect. Is this right?

Nope, you'll see the effect when a flex item would otherwise overflow its parent container.

.box {  background-color: pink;  display: flex;  flex-direction: row;  flex-wrap: wrap;}
.wide { background-color: lightgreen; flex: 0 0 auto; margin: 10px 0; width: 150%;}
.shrink { background-color: lightblue; flex-shrink: 1;}
<div class="box">  <div class="wide shrink">    Wide, shrinks  </div>  <div class="wide">    Wide, won't shrink  </div></div>

How can I make flex items shrink until wrapping is necessary, and then expand to fill the new space?

Here's a snippet that I believe achieves what you want:

<div>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
</div>
</div>
<style>
.container {
display: flex;
max-width: 1200px;
flex-wrap: wrap;
}

.box {
outline: solid red 1px;
min-width: 400px;
flex-grow: 2;
/* flex: 2 0 50%; */ /* If you want to ensure that you never get more than 2 items per row */
}
</style>

In sum, the property you want is flex-grow: it ensures that the component will fill up available space on its row up to the specified factor (in this case 2, to go from 400px width up to 800px).

If it's important not to fit more than two elements on a row on wider screens, I added an alternative flex property for that which uses a flex-basis of 50% to make the components "greedier" in flowing onto a row than they would be otherwise.

Making flexbox shrink to size before wrapping

The functionality I want is there, but I had to set flex-basis: 100px and flex-grow: 1 in .outer-item to make it work, which has the undesirable effect of making both items the same width and spreading them in the available space.

You have outer-wrapper set to display: flex, which acts like a block-level container (i.e., it will occupy all available space on the line).

Instead, use display: inline-flex, which will consume only enough width to accommodate the content.

revised codepen

Make flex items wrap only if they reach their min-width

Gotcha!

Setting .menu to wrap, and allowing items to grow + adding max-width: fit-content; makes it.

Intrinsic size is kinda cutting edge but graceful degradation ftw.

https://jsfiddle.net/joanva/9zgn3hcm/33/

Shrink before wrapping a list of buttons

You can approximate this using flex-basis:0 combined with flex-grow. I also rely on max-width: max-content; to limit the grow effect:

.container {  display: flex;  flex-grow: 1;  background: grey;  padding: 10px;}
.btn-container { min-width: 50px; display: flex; background: red; padding: 10px; flex-wrap: wrap;}
.container>button { background: blue; color: white;}
.btn-container button { min-width: 50px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-basis:0; flex-grow:1; max-width: max-content;}
<div class="container">  <div class="btn-container">    <Button>    hello world  </Button>    <Button>    hello hello hello world  </Button>    <Button>    hello hello hello world  </Button>    <Button>    hello hello hello world  </Button>  </div>  <button>    Button adder  </button></div>

Why do flex items wrap instead of shrink?

The flex-shrink property often comes in handy in a single-line flex container (flex-wrap: nowrap).

In other words, when the flex items cannot wrap, flex-shrink will enable them to shrink when the container is too small (the spec calls this negative free space). This has the effect of preventing flex items from overflowing the container.

However, in a multi-line flex container (flex-wrap: wrap) no negative free space is created most of the time because flex items can create additional lines. An exception is when a multi-line container in, let's say, row-direction, is narrow enough to wrap all items. This leaves items stacked in a single column. Now they will shrink or hold firm, depending on flex-shrink (demo).

You have a row-direction, wrap-enabled flex container with three flex items.

  • div #1 ~ flex: 1 0 200px
  • div #2 ~ flex: 1 1 400px
  • div #3 ~ flex: 1 0 200px

When the container is greater than 800px, all items stay on the line.

When the container breaks below 800px, div #3 will wrap (there is no need to shrink, even if it could).

At the 600px mark (the combined width of divs #1 & #2), div #2 wraps. Again, no need to shrink.

#container {  display: flex;  flex-direction: row;  flex-wrap: wrap;}div:nth-child(1) {  flex: 1 0 200px;  height: 200px;  background-color: lightgreen;}div:nth-child(2) {  flex: 1 1 400px;  height: 200px;  background-color: lightyellow;}div:nth-child(3) {  flex: 1 0 200px;  height: 200px;  background-color: lightblue;}
<div id="container">  <div></div>  <div></div>  <div></div></div>


Related Topics



Leave a reply



Submit