skip to Main Content

I’m very confused on why my flex-shrink isn’t working until I set a fixed width or height on the item I want shrunk faster than the others.

https://codepen.io/MH-123/pen/ExJWQWq

You can see here how the left and right column shrink at the same rate, and the flex-shrink doesn’t seem to affect it. But if you change colLeft and colRight’s width to 300px for example, once the container shrinks to 600px and less, THEN the flex-shrink starts kicking in.
I want to know how I can make the flex-shrink activate right away without setting the fixed width of the left column.

If the only way to achieve this is to set an arbitrary width to flex items, what’s the best practice? Using px? em?

*, 
*::before, 
*::after {
  box-sizing: border-box;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  -ms-box-sizing: border-box;
  -o-box-sizing: border-box;
}

body {
  margin: 0;
  height: 100vh;
  width: 100vw;
  border: 2px solid black;
}

.container {
  width: 100%;
  height: 100%;

  border: 2px solid blue;

  display: flex;
  justify-content: center;
  align-items: center;
  flex: row nowrap;
}

.colLeft, .colRight {
  height: 100%;
  width: 50%;
  border: 2px solid red;
  
  display: flex;
  flex-flow: column nowrap;
  justify-content: space-evenly;
  align-items: center;
  align-content: space-around;
}
.colLeft {
  flex: 1 10 auto;
}
.colRight {
  flex: 1 1 auto;
}
<body>
  <div class="container">
    <div class="colLeft">
      1
    </div>
    <div class="colRight">
      2
    </div>
  </div>
</body>

3

Answers


  1. You should only need flex: 10; respective flex: 1;.
    E. g. you use flex-basis, not flex-shrink.
    There is nice explanation of how flexbox works.

    *, 
    *::before, 
    *::after {
      box-sizing: border-box;
      -webkit-box-sizing: border-box;
      -moz-box-sizing: border-box;
      -ms-box-sizing: border-box;
      -o-box-sizing: border-box;
    }
    
    body {
      margin: 0;
      height: 100vh;
      width: 100vw;
      border: 2px solid black;
    }
    
    .container {
      width: 100%;
      height: 100%;
    
      border: 2px solid blue;
    
      display: flex;
      justify-content: center;
      align-items: center;
      flex: row nowrap;
    }
    
    .colLeft, .colRight {
      height: 100%;
      width: 50%;
    
      border: 2px solid red;
      
      display: flex;
      flex-flow: column nowrap;
      justify-content: space-evenly;
      align-items: center;
      align-content: space-around;
    }
    .colLeft {
      flex: 1;
    }
    .colRight {
      flex: 10;
    }
    <body>
      <div class="container">
        <div class="colLeft">
          1
        </div>
        <div class="colRight">
          2
        </div>
      </div>
    </body>
    Login or Signup to reply.
  2. You only have to change the width to 100% from 50% in

    .colLeft, .colRight {
      height: 100%;
      width: 100%; //instead of 50%
    
      border: 2px solid red;
      
      display: flex;
      flex-flow: column nowrap;
      justify-content: space-evenly;
      align-items: center;
      align-content: space-around;
    }
    
    *, 
    *::before, 
    *::after {
      box-sizing: border-box;
      -webkit-box-sizing: border-box;
      -moz-box-sizing: border-box;
      -ms-box-sizing: border-box;
      -o-box-sizing: border-box;
    }
    
    body {
      margin: 0;
      height: 100vh;
      width: 100vw;
      border: 2px solid black;
    }
    
    .container {
      width: 100%;
      height: 100%;
    
      border: 2px solid blue;
    
      display: flex;
      justify-content: center;
      align-items: center;
      flex: row nowrap;
    }
    
    .colLeft, .colRight {
      height: 100%;
      width: 100%;
      border: 2px solid red;
      
      display: flex;
      flex-flow: column nowrap;
      justify-content: space-evenly;
      align-items: center;
      align-content: space-around;
    }
    .colLeft {
      flex: 1 10 auto;
    }
    .colRight {
      flex: 1 1 auto;
    }
    <body>
      <div class="container">
        <div class="colLeft">
          1
        </div>
        <div class="colRight">
          2
        </div>
      </div>
    </body>
    Login or Signup to reply.
  3. Flexbox works by distributing space. If there is more space than content, it distributes the extra space to it’s children based on their ratios of flex-grow. If there is space missing and children do not fit, they are shrunk, if possible, according to their ratios of flex-shrink.

    The basis for calculating if there is enough space if flex-basis and if none is defined, it uses auto which is roughly speaking the natural size of the element.

    If you do not specify any width or flex-basis for the children, it’s based on the content the children have, in your example, the "1" and "2" respectively. You’re specifying the flex-grow to be 1 and there is a lot of extra space, the content of the flex items is small, so what it does is that it takes all that extra space and distributes it 1:1 to the two elements. This is why if the content was "111111" and "2", they wouldn’t be equal size. Only the empty space gets distributed, so one would be "size of 111111 + 50% of empty space", the other would be "size of 2 + 50% of empty space" which is not the same, 111111 is wider.

    As there is enough space, flex-shrink is never even considered.

    If you put in a long long text like Lorem Ipsum, then the size of these elements would be larger than the size of the container and instead of distributing extra space 1:1, it has to shrunk them in 1:10.

    As soon as you specify the width of the elements to be 50%, you’re saying that both elements fit perfectly and there is no growing or shrinking at all, 50% + 50% = 100% all good.

    If you specify the width of the items to be 100%, then they are 200% of container together, so shrinking kicks in and flexbox shrinks it in 1:10 ratio again.

    This is what you found out yourself, so hope this explanation helps. It’s always either growing (extra space available) or shrinking (not enough space) based on basis (or content itself if no basis/width is used).

    However, even the shrinking considers the basis! If you have a loooong text in left column and short in right column, the columns will not be 1:10 wide, they will be shrunk at 1:10 ratio after taking in the basis:

    div {
      display: flex;
      width: 400px;
    }
    
    p:first-child {
      flex-shrink: 10;
    }
    
    p:last-child {
      flex-shrink: 10;
    }
    
    div p {
      border: 1px solid red;
    }
    <div>
    <p>Some pretty long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long text
    </p>
    <p>Short text short text short text
    </p>
    </div>
    
    <p>The items are not 1:10 in size, they are shrunk in 1:10 starting from their content basis. In my browser, they are 340px and 60px respectively, so definitely not 1:10. And that's because the right column has smaller basis.

    There is a lot going on and we have not even added margins and justify-content, that’s where the fun begins!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search