Prevent Flex Grow Before The Content is Full [duplicate] - css

I have 3 buttons in a row which all vary in width. I want them to all gain width the same to fill the remaining width of the row, so the widest will still be wider than the others etc.
You can see below that what I've tried to do with flex has resulted in all the buttons being the same width. I know flex-grow can be used to proportionally grow each item, but I can't work out how to get them all to grow in relation to their original size.
You can see in the second row that the blue item is larger than the other two. I just want all three to expand from their current size equally to fill the row.
Thanks
.row-flex {
width: 100%;
display: flex;
flex-direction: row;
}
.button {
flex: 1;
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>

Short Answer
Switch from flex: 1 to flex: auto.
Explanation
The flex-grow property factors in two key pieces of data:
The free space in the row / column where it is being used.
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:
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

Not sure if this is entirely what you are after, but if you just set flex-grow:1 instead of flex:1;, I think that is your required result:
.row-flex {
width: 100%;
display: inline-flex;
flex-direction: row;
}
.button {
flex-grow: 1;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>

Using flex property you can set proportions:
.button {
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.row {
display: flex;
}
.button--1 {
background: red;
flex: 1 1 auto;
}
.button--2 {
background: green;
flex: 2 1 auto;
}
.button--3 {
background: blue;
flex: 3 1 auto;
}
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>

Minimalistic answer with (hopefully useful, explanatory) alternatives:
HTML:
<div class="row-flex">
Single
Larger title
Another really large title
</div>
CSS:
.row-flex {
display: flex;
}
.button {
flex-grow: 1; /* make the item grow proportionally to its original size */
/* default value is 0, the item does not grow */
/* a meaningful default for flexbox items positioning with */
/* justify-content: <value>; */
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
The following CSS declarations also work because all they do is override the default flex-grow: 0; to the (for the desired behavior required) flex-grow: 1;:
.button {
flex: auto;
...
}
which is a shorthand for:
.button {
flex: 1 1 auto;
...
}
which is a shorthand for:
.button {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
...
}

Related

Nested row flexbox with wrapping on multiple levels

I am making responsive design where elements wrap to next line in certain way when there is not enough space, however I cannot make it working.
Requirements:
There are 3 elements (actually more, but this is minimal example), all with automatic size depending on their content: one aligned on the left, two - on the right.
They are placed inside container which always spans at least 100% width of parent.
If there is not enough space for elements to be all on one line, then right element should begin to wrap to next line, while still all being to the right of left element.
If there is still not enough space, only then right elements go under left one.
If there is still not enough space, then container expands in size.
Here are examples how it should work (red lines represent viewport borders):
Here is code I come up with so far, but it starts wrapping immediately on outer level, not on innermost as I need:
html, body {
width: 100%;
height: 100%;
}
* {
margin: 0;
padding: 0;
flex: 0 0 auto;
}
#container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
overflow: hidden;
width: 100%;
min-width: min-content;
background-color: rgb(224, 191, 146); /* for visibility */
}
#child-left {
background-color: rgb(92, 189, 40); /* for visibility */
/* imitate content for demo, in actual code size is not set */
width: 50vw;
height: 50px;
}
#child-right {
display: flex;
flex-flow: row wrap;
background-color: rgb(111, 72, 20); /* for visibility */
}
#grandchild-right-1 {
background-color: rgb(40, 102, 189); /* for visibility */
/* imitate content for demo, in actual code size is not set */
width: 200px;
height: 20px;
}
#grandchild-right-2 {
background-color: rgb(189, 40, 112); /* for visibility */
/* imitate content for demo, in actual code size is not set */
width: 200px;
height: 20px;
}
<div id="container">
<div id="child-left">1</div>
<div id="child-right">
<div id="grandchild-right-1">2</div>
<div id="grandchild-right-2">3</div>
</div>
</div>
You can achieve this by using flex: 1.
Remember that flex is a shorthand property for flex: 1 1 0 or flex-grow: 1, flex-shrink: 1 and flex-basis: 0.
As a result, this makes the elements take any empty space in the container, hopping to the next line if theres no space left.
https://css-tricks.com/understanding-flex-grow-flex-shrink-and-flex-basis/

Can someone explain me what is flex property? [duplicate]

This question already has answers here:
The difference between flex:1 and flex-grow:1
(2 answers)
Closed 3 years ago.
Hello currently I'm learning flexbox, and I've watched a lot tutorials but I couldn't figure out what does flex property do? Some explanation and links that explain what it does would be really helpful. Thanks.
As T. Evans mentioned, the flex property is shorthand for three other properties: flex-grow, flex-shrink, and flex-basis. You can set the values of each property by giving the flex property three values, in this order:
flex: [flex-grow] [flex-shrink] [flex-basis]
For example, flex: 0 1 auto;
Now, let’s briefly review what each of those three properties means.
Flex-grow
We use this property on a child element of a flex-box. It sets how large the element will be in proportion to the other elements. The default value of flex-grow is 0, so setting flex-grow to larger than 0 will make the element larger than other elements. (You can’t set it to a negative number, though.)
Example 1: Here, we use flex-grow to make one element twice as large as the other. A flex-grow of 2 on one element and 1 on the other element means that the elements will have a 2-to-1 size ratio. Setting one flex-grow to 8 and the other to 4 would do the exact same thing, since 2:1 is the same ratio as 8:4.
#flexbox {
display: flex;
width: 100%;
height: 300px;
border: 1px solid black;
}
#big {
flex-grow: 2;
background-color: lavender;
}
#small {
flex-grow: 1;
background-color: lightblue;
}
<div id="flexbox">
<div id="big">BIG</div>
<div id="small">SMALL</div>
</div>
JSFiddle
Example 2: Here, we set flex-grow on only one element while leaving the other at its default of 0. This makes the element grow to fill as much space as possible. We can use any value for flex-grow and it will work exactly the same, as long as the other element has flex-grow: 0;
#flexbox {
display: flex;
width: 100%;
height: 300px;
border: 1px solid black;
}
#big {
flex-grow: 5;
background-color: lavender;
}
#small {
/* flex-grow is 0 by default */
background-color: lightblue;
}
<div id="flexbox">
<div id="big">BIG</div>
<div id="small">SMALL</div>
</div>
JSFiddle
Flex-shrink
This property works similarly to flex-grow, but the ratio describes how much smaller one element should be than another. Also, the default value is one.
Example: If we set one element’s flex-shrink to 2 and the others' to 1, when the parent element is too small to fit every element comfortably and the children must shrink, that element will shrink more than the other elements.
#flexbox {
display: flex;
width: 100%;
height: 300px;
border: 1px solid black;
}
#flexbox div {
flex-grow: 1;
border: 1px solid purple;
background-color: lavender;
}
#flexbox #small {
flex-shrink: 4;
background-color: lightblue;
}
<div id="flexbox">
<div>NORMAL</div>
<div id="small">SMALL</div>
<div>NORMAL</div>
<div>NORMAL</div>
<div>NORMAL</div>
</div>
JSFiddle
Flex-basis
This property sets the initial size of the element. Its value can be either auto, which sets the initial size automatically, or a number of pixels or other size units (like % or vw, for example.) The default value is auto.
Example: Here, we set most of the elements to have an initial size of 50px and set their flex-grow to 1 so that they will grow to fill the space. However, one element has a flex-basis of 100px, so it will be larger than the other elements. Try resizing the window to see how this example behaves.
#flexbox {
display: flex;
width: 100%;
height: 300px;
border: 1px solid black;
}
#flexbox div {
flex-grow: 1;
flex-basis: 50px;
border: 1px solid purple;
background-color: lavender;
}
#flexbox #large {
flex-basis: 100px;
background-color: lightblue;
}
<div id="flexbox">
<div>NORMAL</div>
<div id="large">LARGE</div>
<div>NORMAL</div>
<div>NORMAL</div>
<div>NORMAL</div>
</div>
JSFiddle
Putting it all together
As we mentioned before, the flex property combines all three of those properties into one. If we wanted to set the flex-grow of an element to 1, the flex-shrink to 2, and the flex-basis to 100px, we could use flex and shorten this:
#child {
flex-grow: 1;
flex-shrink: 2;
flex-basis: 100px;
}
To this:
#child {
flex: 1 2 100px;
}
Flex Property is referring to a shorthand.
Basically it looks like this : flex: <flex-grow> <flex-shrink> <flex-basis>
This refers to how the items work more in a display: flex...
For more on this I would suggest looking at the following links:
W3 Schools
CSS Tricks
MDN

Flexbox is growing the more items it has, but shouldn't [duplicate]

I have 3 buttons in a row which all vary in width. I want them to all gain width the same to fill the remaining width of the row, so the widest will still be wider than the others etc.
You can see below that what I've tried to do with flex has resulted in all the buttons being the same width. I know flex-grow can be used to proportionally grow each item, but I can't work out how to get them all to grow in relation to their original size.
You can see in the second row that the blue item is larger than the other two. I just want all three to expand from their current size equally to fill the row.
Thanks
.row-flex {
width: 100%;
display: flex;
flex-direction: row;
}
.button {
flex: 1;
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Short Answer
Switch from flex: 1 to flex: auto.
Explanation
The flex-grow property factors in two key pieces of data:
The free space in the row / column where it is being used.
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:
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
Not sure if this is entirely what you are after, but if you just set flex-grow:1 instead of flex:1;, I think that is your required result:
.row-flex {
width: 100%;
display: inline-flex;
flex-direction: row;
}
.button {
flex-grow: 1;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
Using flex property you can set proportions:
.button {
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.row {
display: flex;
}
.button--1 {
background: red;
flex: 1 1 auto;
}
.button--2 {
background: green;
flex: 2 1 auto;
}
.button--3 {
background: blue;
flex: 3 1 auto;
}
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Minimalistic answer with (hopefully useful, explanatory) alternatives:
HTML:
<div class="row-flex">
Single
Larger title
Another really large title
</div>
CSS:
.row-flex {
display: flex;
}
.button {
flex-grow: 1; /* make the item grow proportionally to its original size */
/* default value is 0, the item does not grow */
/* a meaningful default for flexbox items positioning with */
/* justify-content: <value>; */
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
The following CSS declarations also work because all they do is override the default flex-grow: 0; to the (for the desired behavior required) flex-grow: 1;:
.button {
flex: auto;
...
}
which is a shorthand for:
.button {
flex: 1 1 auto;
...
}
which is a shorthand for:
.button {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
...
}

Make flex-grow expand items based on their original size

I have 3 buttons in a row which all vary in width. I want them to all gain width the same to fill the remaining width of the row, so the widest will still be wider than the others etc.
You can see below that what I've tried to do with flex has resulted in all the buttons being the same width. I know flex-grow can be used to proportionally grow each item, but I can't work out how to get them all to grow in relation to their original size.
You can see in the second row that the blue item is larger than the other two. I just want all three to expand from their current size equally to fill the row.
Thanks
.row-flex {
width: 100%;
display: flex;
flex-direction: row;
}
.button {
flex: 1;
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Short Answer
Switch from flex: 1 to flex: auto.
Explanation
The flex-grow property factors in two key pieces of data:
The free space in the row / column where it is being used.
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:
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
Not sure if this is entirely what you are after, but if you just set flex-grow:1 instead of flex:1;, I think that is your required result:
.row-flex {
width: 100%;
display: inline-flex;
flex-direction: row;
}
.button {
flex-grow: 1;
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
<div class="row-flex">
Single
Larger title
Another really large title
</div>
Using flex property you can set proportions:
.button {
display: inline-block;
padding: 10px;
color: #fff;
text-align: center;
}
.row {
display: flex;
}
.button--1 {
background: red;
flex: 1 1 auto;
}
.button--2 {
background: green;
flex: 2 1 auto;
}
.button--3 {
background: blue;
flex: 3 1 auto;
}
<br/>
<div class="row">
Single
Larger title
Another really large title
</div>
Minimalistic answer with (hopefully useful, explanatory) alternatives:
HTML:
<div class="row-flex">
Single
Larger title
Another really large title
</div>
CSS:
.row-flex {
display: flex;
}
.button {
flex-grow: 1; /* make the item grow proportionally to its original size */
/* default value is 0, the item does not grow */
/* a meaningful default for flexbox items positioning with */
/* justify-content: <value>; */
padding: 10px;
color: #fff;
text-align: center;
}
.button--1 {
background: red
}
.button--2 {
background: green;
}
.button--3 {
background: blue;
}
The following CSS declarations also work because all they do is override the default flex-grow: 0; to the (for the desired behavior required) flex-grow: 1;:
.button {
flex: auto;
...
}
which is a shorthand for:
.button {
flex: 1 1 auto;
...
}
which is a shorthand for:
.button {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
...
}

Chrome ignoring flex-basis in column layout [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I'm having trouble getting Chrome to pay attention to the flex-basis part of flex: 1 1 25% in a flex-direction: column layout. It works fine in a row layout.
The snippet below demonstrates the problem: the yellow, blue, and pink bars are flex-basis 50px, 25%, and 75%, shown in both column and row flex directions.
If you run it in Firefox (or IE11 or Edge) both column and row divide up the area as expected:
But if you run it in Chrome (47) or Safari (9.0.3), the column layout on the left seems to ignore the flex-basis entirely -- the heights of the bars seem to have no relation to the flex-basis:
The only difference between left and right is the flex-direction.
.container {
width: 400px;
height: 200px;
display: flex;
background: #666;
position: relative;
}
.layout {
flex: 1 1 100%; /* within .container */
margin: 10px;
display: flex;
}
.row {
flex-direction: row;
}
.column {
flex-direction: column;
}
.exact {
flex: 1 1 50px;
background: #ffc;
}
.small {
flex: 1 1 25%;
background: #cff;
}
.large {
flex: 1 1 75%;
background: #fcf;
}
<div class="container">
<div class="layout column">
<div class="exact">50px</div>
<div class="small">25%</div>
<div class="large">75%</div>
</div>
<div class="layout row">
<div class="exact">50px</div>
<div class="small">25%</div>
<div class="large">75%</div>
</div>
</div>
I tried adding height: 100% to .column, which makes Chrome pay attention to the flex-basis, but causes a different problem -- the flex gets bigger than its container:
.column {
flex-direction: column;
height: 100%;
}
I gather this is a long-standing webkit bug. Is there any way to work around it? (I'm trying to create some generalized layout components, so hard-coding specific numbers of children or specific pixel heights isn't workable.)
[EDIT] Here's an additional example showing the general problem (and avoiding the margin and total-greater-than-100% issues in the example above):
.container {
width: 300px;
height: 300px;
display: flex;
}
.layout {
flex: 1 1 100%; /* within its flex parent */
display: flex;
background: #ffc;
}
.row {
flex-direction: row;
}
.column {
flex-direction: column;
height: 100%; /* attempted workaround for webkit */
}
.small {
flex: 1 1 30%;
background: #cff;
}
.large {
flex: 1 1 70%;
background: #fcf;
}
div {
/* border/padding just makes divs easier to see --
you can remove all of this without changing the problem */
box-sizing: border-box;
border: 1px solid #999;
padding: 10px;
}
<div class="container">
<div class="layout row">
<div class="small">row: 30%</div>
<div class="large layout column">
<div class="small">row: 70%; col: 30%</div>
<div class="large">row: 70%; col: 70%</div>
</div>
</div>
</div>
Three items to consider:
Sum of all heights greater than 100%
In your .column layout, you have three flex items. Their heights are 75% + 25% + 50px. This by itself exceeds the height: 100% you applied. This does not cause an overflow because you have flex-shrink set to 1.
Margin space
You have specified margin: 10px for both layouts. So there's an extra 20px of height from the top and bottom margins. In the .column layout, this does indeed cause an overflow on Chrome.
Adjust for those extra 20px, and the overflow is gone:
.column {
flex-direction: column;
height: calc(100% - 20px); /* new */
}
.container {
width: 400px;
height: 200px;
display: flex;
background: #666;
position: relative;
}
.layout {
flex: 1 1 100%; /* within .container */
margin: 10px;
display: flex;
}
.row {
flex-direction: row;
}
.column {
flex-direction: column;
height: calc(100% - 20px); /* NEW */
}
.exact {
flex: 1 1 50px;
background: #ffc;
}
.small {
flex: 1 1 25%;
background: #cff;
}
.large {
flex: 1 1 75%;
background: #fcf;
}
<div class="container">
<div class="layout column">
<div class="exact">50px</div>
<div class="small">25%</div>
<div class="large">75%</div>
</div>
<div class="layout row">
<div class="exact">50px</div>
<div class="small">25%</div>
<div class="large">75%</div>
</div>
</div>
Percentage Heights: Chrome / Safari vs Firefox / IE
The reason the flex items in Chrome / Safari don't recognize their percentage heights is because Webkit browsers are adhering to a more traditional interpretation of the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to auto.
auto The height depends on the values of other properties.
In other words, if you want an element to have a percentage height, then you must specify a height on the parent.
The traditional interpretation of this language is that "height" means the value of the height property. Although it's unclear from the language exactly what "height" means, the height property requirement has been the predominant implementation. I've never seen min-height, max-height or other forms of height work on a parent when dealing with percentage values.
Recently, however, as noted in this question (and another one and another one and another one), Firefox (and IE, apparently) has broadened its interpretation to accept flex heights, as well.
It's not clear which browser is more compliant with the standard.
It doesn't help matters that the height definition hasn't been updated since 1998 (CSS2).
Bottom line, Chrome and Safari resolve percentage heights based on the value of the parent's height property. Firefox and IE11/Edge use the parent's computed flex height.
For now, the simplest cross-browser solution to this problem would be, in my view, using the height property across the board for percentage heights.
UPDATE: More solutions here: Chrome / Safari not filling 100% height of flex parent

Resources