6

Let's say I have a simple flex container with 2 flex items where the flex items' sizes exceed the containers size - where flex-shrink will be used..like so:

.container {
  width: 600px;
  outline: 5px solid;
  display: flex;
}
section {
  flex: 0 1 600px;
  background: salmon;
}
aside {
  flex: 0 1 200px;
  background: aqua;
}
<div class="container">
  <section>
    <h2>Main content here</h2>
  </section>
  <aside>
    <h2>Some side content</h2>
  </aside>
</div>

Codepen demo

In the above example: The container is 600px, the section flex-item has flex basis of 600px and the aside has flex-basis of 200px - so the negative space is 200px.

So being that both flex items have the same flex-shrink factor of 1 - I expected that both flex items would shrink by 100px with the section getting a width of 600px - 100px = 500px and the aside getting 200px - 100px = 100px

But the result was actually that the section shrinks by 150px to 450px and the aside shrinks by 50px to 150px

So then I looked at the spec and I found this:

Note: The flex shrink factor is multiplied by the flex base size when distributing negative space. This distributes negative space in proportion to how much the item is able to shrink, so that e.g. a small item won’t shrink to zero before a larger item has been noticeably reduced.

So now I understand that when calculating flex-shrink on a flex item not only is the flex shrink factor taken into account, but also the flex base size (here, defined by the flex-basis property)

The problem is that I can't seem to do the math to calculate flex-shrink.

So just to continue with the above example: say I change the shrink factor of the section to 2...

.container {
  width: 600px;
  outline: 5px solid;
  display: flex;
}
section {
  flex: 0 2 600px;
  background: salmon;
}
aside {
  flex: 0 1 200px;
  background: aqua;
}
<div class="container">
  <section>
    <h2>Main content here</h2>
  </section>
  <aside>
    <h2>Some side content</h2>
  </aside>
</div>

Codepen demo #2

... the result is that section gets a width of 428px and aside gets a width of 121px

Can someone explain how to calculate this?

Danield
  • 121,619
  • 37
  • 226
  • 255
  • I would use %. Like 60% and 40% or however you think the split should be – mlegg Apr 11 '16 at 14:35
  • 2
    This may help you understand the calculation: http://stackoverflow.com/q/34753491/3597276 – Michael Benjamin Apr 11 '16 at 16:35
  • 2
    @Michael_B thanks, flex-shrink seems to be more complicated than flex-grow and yet there doesn't seem to be much info / blog posts about it with actual calculations....+1 – Danield Apr 11 '16 at 21:12
  • 3
    @Danield, Agreed. `flex-shrink` in my experience has been more complex to sort out than `flex-grow`. That question, along with the answers from @Oriol (here and there) help clear it up. Cheers! – Michael Benjamin Apr 11 '16 at 21:19

1 Answers1

10

Neglecting lots of details, the algorithm is something like this

let sumScaledShrinkFactors = 0,
    remainingFreeSpace = flexContainer.innerMainSize;
for (let item of flexItems) {
  remainingFreeSpace -= item.outerFlexBasis;
  item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor;
  sumScaledShrinkFactors += item.scaledShrinkFactor;
}
for (let item of flexItems) {
  let ratio = item.scaledShrinkFactor / sumScaledShrinkFactors;
  item.innerWidth = item.innerFlexBasis + ratio * remainingFreeSpace;
}

So the formula is like

flexBasis * (1 + shrinkFactor / sumScaledShrinkFactors * remainingFreeSpace)

First case

1*600px + 1*200px ─┐               width 
                   │              ───────
600px * (1 + 1 / 800px * -200px) = 450px 
200px * (1 + 1 / 800px * -200px) = 150px 
                            │     ───────
600px - (600px + 200px) ────┘      600px 

Second case

2*600px + 1*200px ──┐               width 
                    │              ───────
600px * (1 + 2 / 1400px * -200px) ≈ 429px 
200px * (1 + 1 / 1400px * -200px) ≈ 171px 
                             │     ───────
600px - (600px + 200px) ─────┘      600px 
Oriol
  • 274,082
  • 63
  • 437
  • 513