It seems that the content inside a flex div affects its calculated size concerning the flex-grow property. Am I doing something wrong?
In the fiddle pr
The problem is that rows 1-3 have two horizontal margins and row 4 only has one.
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; }
You wrote:
It seems that the content inside a flex div affects its calculated size concerning the
flex-growproperty. Am I doing something wrong?
The source of your problem is not the content inside the flex item.
You wrote:
In the fiddle provided below, you'll see a number pad. All the rows contain 3 numbers except the bottom row. That row should have the '0' be the width of 2 numbers, hence
flex-grow: 2and the ':' be the size of 1 number, henceflex-grow: 1. Am I missing something here?
Yes. Your interpretation of the flex-grow property is incorrect. flex-grow is not intended for defining the size of a flex item. Its job is to distribute free space in the flex container among items.
By applying flex-grow: 1 to a group of flex items, you are telling them to distribute free space evenly among themselves. This is why, in your demo, rows 1, 2 and 3 have equally sized flex items.
When you apply flex-grow: 2, you are telling the flex item to consume twice as much free space as items with flex-grow: 1.
But where does the second 10px margin from the rows above factor into the layout of row 4?
The reason the alignment is off on row 4 is that row 4 has one less margin than the other rows, meaning that row 4 has 10px more free space than the other rows.
You'll notice that if you remove the margin rule you get your desired alignment.
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
/* margin: 5px; */
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.button#number0 {
flex-grow: 2;
}
.button#colon {
flex-grow: 1;
}
So what happens on row four to that second 10px margin?
It gets absorbed by the two flex items.
Here's how
flex-growdistributes the extra space on row four:
- Flex item left (with content "0") has
flex-grow: 2. (.button#number0in your code.)- Flex item right (with content ":") has
flex-grow: 1. (.button#colonin your code.)- The second inter-item margin, which appears only on rows with three flex items, is 10px wide. (The code says 5px around each item, but in CSS horizontal margins never collapse. Moreover, in flexbox, no margins collapse.)
- The sum total of the
flex-growvalues is three. So let's divide 10px by 3. Now we know that the proportion of 1 is 3.33px.- Hence, flex item left gets 6.66px of the extra space, and flex item right gets 3.33px.
- Let's say that flex item left had
flex-grow: 3instead. Then flex item left would get 7.5px, and flex item right would get 2.5px.
The last part of your question says:
The right side of the '0' should be aligned with the 8, 5, and 2 above it. It's a bit off.
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; }
jsFiddle demo
References:
With the advent of CSS Grid, the code for this entire layout can be greatly simplified.
.numbers {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(26%, 1fr));
grid-gap: 10px;
}
#number0 {
grid-column: span 2;
}
/* non-essential decorative styles */
.button {
display: flex;
justify-content: center;
align-items: center;
border-radius: 5px;
border: 1px solid gray;
}