Flex-Grow Not Sizing Flex Items as Expected

flex-grow not sizing flex items as expected

Short Analysis

The problem is that rows 1-3 have two horizontal margins and row 4 only has one.

Sample Image

With horizontal margins at 10px each, row 4 has 10px more free space than the other rows. This throws off the alignment of the columns.

Because flex-grow applies only to free space, and is heavily influenced by content and margins, it's not the most secure way to size flex items.

Try flex-basis instead. Add this to your code:

.button    { flex-basis: 33.33%; }
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }

.numbers {    display: flex;    flex-direction: column;}
.row { display: flex; flex-direction: row; flex-grow: 1; justify-content: space-between;}
.button { display: flex; flex-basis: 33.33%; justify-content: center; align-items: center; margin: 5px; border-radius: 5px; border: 1px solid gray; background: rgba(255, 255, 255, 0.2); cursor: pointer;}
#number0 { flex-basis: calc(66.67% + 10px); }* { box-sizing: border-box; }
<div class="numbers">    <div class="row">        <div class="button number" id="number1">1</div>        <div class="button number" id="number2">2</div>        <div class="button number" id="number3">3</div>    </div>    <div class="row">        <div class="button number" id="number4">4</div>        <div class="button number" id="number5">5</div>        <div class="button number" id="number6">6</div>    </div>    <div class="row">        <div class="button number" id="number7">7</div>        <div class="button number" id="number8">8</div>        <div class="button number" id="number9">9</div>    </div>    <div class="row">        <div class="button number" id="number0">0</div>        <div class="button" id="colon">:</div>    </div></div>

Inconsistency between flex-grow and width on flex items

You need to set the flex-basis property on your flex-items to 0%

#flex-item-1 {
flex-basis: 0%;
flex-grow: 3;
background-color: tomato;
/* width: 75%; */
}

#flex-item-2 {
flex-basis: 0%;
flex-grow: 1;
background-color: pink;
/* width: 25%; */
}

It specifies the initial size of the flex item, before any available space is distributed according to the flex factors. When omitted from the flex shorthand, its specified value is the length zero. Source: mdn

Stackblitz example

flex grow not working as described

You need to add flex-grow:1; to .d1 . Because flex-grow determines how the remaining space is divided between flex-items and how much each item receives.

So if you don't set flex-grow for some items, they won't get that space, and you won't get elements' widths as you expect.

.d1{
flex-grow: 1;
}

.parent {  display: flex;  border: 1px solid rgba(0, 0, 0, .5);  height: 300px;  width: 300px;  flex-flow: row wrap;  justify-content: center;  align-items: center;
}
.parent div { width: 50px; height: 50px; background-color: blue; margin: 1px; color: white; text-align: center; line-height: 50px;}
.d1 { flex-grow: 1;}
.d2 { flex-grow: 3;}
<div class="parent">  <div class="d1">1</div>  <div class="d2">2</div>
</div>

Do not fill the width of growable flex containers

I think it would be better to use css grid instead:

* {
box-sizing: border-box;
margin: 0;
padding:0;
}

article {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;

width: 800px;
padding: 10px;
border: 1px solid blue;
}

section {
padding: 10px;
border: 1px solid black;
}

Can I shrink flexbox items into same size when flex items are bigger than the flex container?

I would use display: grid instead of display: flex to achieve this. Here is an example:

.flex-container {  font-size: 12px;  display: grid;  grid-template-columns: 1fr;  grid-template-rows: repeat(2, minmax(minmax(0, auto), 50%));  width: 200px;  height: 500px;  border: 1px solid #dadfe3;}
.flex-item { min-height: 0; overflow: auto; margin: 0 20px;}
.flex-item div { margin: 4px 0; background-color: #f0f9ff; color: #2f88ff;}
<body>  <div class="flex-container">    <div class="flex-item">      <input type="text" placeholder="filter 1">      <div>item content 1</div>      <div>item content 2</div>      <div>item content 3</div>      <div>item content 4</div>      <div>item content 5</div>      <div>item content 6</div>    </div>    <div class="flex-item">      <input type="text" placeholder="filter 2">      <div>item 1</div>      <div>item 2</div>      <div>item 3</div>      <div>item 4</div>      <div>item 5</div>      <div>item 6</div>      <div>item 7</div>      <div>item 8</div>      <div>item 9</div>      <div>item 10</div>      <div>item 11</div>      <div>item 12</div>      <div>item 13</div>      <div>item 14</div>      <div>item 15</div>    </div>  </div></body>

Flex-grow with width property on element

Simply because the flex-grow will make the element to consume the free space. In your case the first element has 100px of width and the other one is having width equal to its content so the free space is (width of container - 100px - content of box2). This free space will be split equally and added to both element and it's logical that the first one will be bigger since initially it was already bigger.

In your example, the second element is about 29px and if we fix the width of the container to 600px for example, we will have a free space equal to 471px so both elements will end with 335.5px and 264.5px of width.

.wrapper {  display: flex;  width:600px;}
.box1 { background: red; width: 100px; flex-grow: 1;}
.box2 { background: green; flex-grow: 1;}
<div class="wrapper">  <div class="box1">One</div>  <div class="box2">Two</div></div>

Make flex-grow expand items based on their original size

Short Answer

Switch from flex: 1 to flex: auto.



Explanation

The flex-grow property factors in two key pieces of data:

  1. The free space in the row / column where it is being used.
  2. The value of the flex-basis property.

Distribution of Free Space

The flex-grow property distributes free space in the container among flex items in the same line.

If there is no free space, flex-grow has no effect.

If there is negative free space (i.e., the total length of flex items is greater than the length of the container), then flex-grow has no effect and flex-shrink comes into play.


The flex-basis factor

When flex-basis is 0, flex-grow ignores the size of the content in flex items and treats all space on the line as free space.

This is absolute sizing. All space on the line is distributed.

When flex-basis is auto, the size of the content in flex items is first deducted to determine the free space in each item. flex-grow then distributes the free space among items (based on each item's flex-grow value).

This is relative sizing. Only extra space on the line is distributed.

Here's an illustration from the spec:

Sample Image


Examples:

  • flex: 1 (absolute sizing)

This shorthand rule breaks down to: flex-grow: 1 / flex-shrink: 1 / flex-basis: 0

Applied to all flex items, this will make them equal length, regardless of content. (Note that in some cases an override of default minimum sizing will be necessary for this effect to occur.)

  • flex-grow: 1 (relative sizing)

This rule by itself will factor in both content size and available space, because the default value for flex-basis is auto.

  • flex: auto (relative sizing)

This shorthand factors in both content size and available space because it breaks down to:

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

More variations here: 7.1.1. Basic Values of flex

additional keywords for search: difference between flex-basis auto 0 flex 1 auto

How to prevent content from re-sizing a flex item?

When you tell a flex item to flex: 3 (Item 6) or flex: 1 (Items 5 & 7), here's how that shorthand property breaks down:

flex: ?  =  <flex-grow>, <flex-shrink>, <flex-basis>

flex: 3 = flex-grow: 3, flex-shrink: 1, flex-basis: 0

flex: 1 = flex-grow: 1, flex-shrink: 1, flex-basis: 0

In both cases, the flex-shrink factor is 1, meaning the flex item is allowed to shrink proportionally.

To prevent the flex items from shrinking, which may be causing the misalignment, I would change the flex-shrink to 0.

Instead of flex: 3 and flex: 1 try:

flex: 3 0 0;
flex: 1 0 0;

More details in the flexbox spec: 7.1.1. Basic Values of flex


But you may have another problem. You wrote:

Note that items 5 and 7 are setup the same way in css, with flex values of 1. I.e. item 6 is 3 times the height of items 5 and 7. As such, when item 6 resizes, the 3:1 ratio is maintained.

This is not how the flex-grow property works.

By applying flex-grow: 3 to a flex item you are telling it to consume three times more available space than flex items with flex-grow: 1. This does not necessarily mean Item 6 will be three times the size of Items 5 and 7.

Learn more about how flex-grow works here: flex-grow not sizing flex items as expected

As an alternative sizing method, you may want to use the flex-basis property. Try flex: 0 0 60% on Item 6, and flex: 0 0 20% on Items 5 and 7.



Related Topics



Leave a reply



Submit