7

I wonder if anyone could give me a simple intro about how flexbox layout gets calculated, especially in which priority order, for example:

    <div id="container" style="display: flex; flex-direction: row; flex-wrap:wrap;">
    <div style="flex: 1 0 200px; height:200px; background-color: lightgreen;"></div>
    <div style="flex: 1 1 400px; height:200px; background-color: lightyellow;"></div>
    <div style="flex: 1 0 200px; height:200px; background-color: lightblue;"></div>
</div>

I find it interesting that if I make the container width smaller than 600px; the wrap will take effect first before the shrinking (I set the second yellow block to flex: 1 1 400px;) which turn into 3 rows, then the shrinking take effect until container reach 200px;

I wonder what is the order/rule the flexbox layout get decided? Why it does not just shrink from 400 block?

And even I also set all three blocks to flex: 1 1 their basis size; the wrap still happens first.

Thanks

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Kuan
  • 11,149
  • 23
  • 93
  • 201

2 Answers2

9

See Flex Layout Algorithm in the spec:

  1. Initial Setup
  2. Line Length Determination
  3. Main Size Determination
  4. Cross Size Determination
  5. Main-Axis Alignment
  6. Cross-Axis Alignment
  7. Resolving Flexible Lengths
  8. Definite and Indefinite Sizes
  9. Intrinsic Sizes

First, at step 3, flex items are collected into flex lines.

Later, at step 7, they flex (grow, shrink, or remain unaltered).

So yes, flex-wrap, which determines how flex items are collected into flex lines, has more "priority" than flex-shrink.

Oriol
  • 274,082
  • 63
  • 437
  • 513
4

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>

From the spec:

flex-shrink

[This property] specifies the flex shrink factor, which determines how much the flex item will shrink relative to the rest of the flex items in the flex container when negative free space is distributed.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Thanks for explanation – Kuan Sep 12 '16 at 20:29
  • 1
    I do not understand why the spec does not state that flex-shrink only applies to single-line flex containers. It would be a simple thing to state under the flex-shrink property description, but instead they are determined to make it as confusing as possible. – Magnus Jan 26 '19 at 00:48
  • 1
    @Magnus, that wouldn't be accurate. In a multi-line container (`wrap`), let's say in row-direction, items may wrap before they can shrink. But eventually, when they are all stacked in a single column, they will shrink or hold firm, depending on `flex-shrink`. Test it out: https://jsfiddle.net/19q4aeh5/ – Michael Benjamin Jan 26 '19 at 01:02
  • Thanks for the quick feedback. That's interesting. But, isn't it the case that if we set a smaller width on the container, then one (or more) additional rows would just be added? How could items then ever shrink from their main size, if wrapping always occurs first. – Magnus Jan 26 '19 at 01:07
  • Not entirely sure what you mean. Can you post an illustration (maybe using the code in my previous comment)? @Magnus – Michael Benjamin Jan 26 '19 at 01:14
  • Hi Michael, thanks again. I tried your example and adding shrink (uncommenting) made no difference. – Magnus Jan 26 '19 at 11:51
  • Ohhh, sorry, this was key: "When they are all stacked in a SINGLE column". Sorry. I got it now. – Magnus Jan 26 '19 at 12:00
  • I am still very surprised the spec does not mention this behavior under `flex-shrink` or under Flex Lines. It would be very easy to say: If `flex-wrap` is set to `wrap`, then `flex-shrink` has no effect until all items flow along a single cross-axis column/row (i.e. every item is wrapped onto its own line). – Magnus Jan 26 '19 at 12:04