Understanding flex-grow - html

I have 3 divs and if I give flex: 0.5 to first two divs, the last div should move to the next line if I have given flex-wrap: wrap. Please correct if I am wrong.
Following is my html / css:
.parent {
display: flex;
height: 100px;
background-color: red;
flex-wrap: wrap;
}
.child-1 {
background-color: green;
flex: 0.5;
}
.child-2 {
background-color: yellow;
flex: 0.5;
}
.child-3 {
background-color: pink;
}
<div class="parent">
<div class="child-1">LOREN IPSUM LOREN IPSUM</div>
<div class="child-2">LOREN IPSUMLOREN IPSUMLOREN IPSUM</div>
<div class="child-3">LOREN IPSUMLOREN IPSUM</div>
</div>
Please check JSFiddle for this.
Thanks in advance.

The flex-grow property is designed to distribute free space in the container among flex items.
It is not intended for directly or precisely sizing flex items.
From the spec:
flex-grow ... determines how much the flex item will grow relative
to the rest of the flex items in the flex container when positive free
space is distributed.
Hence, flex-grow will not force items to wrap. Here's your example with flex-grow: 1000: demo
To define a length of a flex item use width, height or flex-basis.
Explaining flex-grow: 0.5
When you apply flex:0.5, you're using the flex shorthand property to say this:
flex-grow: 0.5
flex-shrink: 1
flex-basis: 0
The flex-grow component represents a proportion. In this case, it's telling flex items to consume half of the available space in the container relative to the flex-grow factor of its siblings.
So, for instance, if the container were width: 600px and the total width of the three divs was 450px, this would leave 150px in free space (demo).
If each item had flex-grow: 1, then each item would consume 50px of the extra space, and each item would compute to width: 200px (demo).
But in your code, two items have flex-grow: 0.5, and the last item has flex-grow: 0, so here's how it breaks down:
div#1 will get 75px (half of the available space)
div#2 will get 75px (half of the available space)
div#3 will get 0 (because its flex-grow is 0)
These are the computed values now:
div#1 = width: 225px
div#2 = width: 225px
div#3 = width: 150px
demo
.parent {
display: flex;
flex-wrap: wrap;
height: 100px;
background-color: red;
width: 600px;
}
.parent > div {
flex-basis: 150px;
}
.child-1 {
flex: 0.5;
background-color: green;
}
.child-2 {
flex: 0.5;
background-color: yellow;
}
.child-3 {
background-color: pink;
}
<div class="parent">
<div class="child-1">LOREN IPSUM LOREN IPSUM</div>
<div class="child-2">LOREN IPSUMLOREN IPSUMLOREN IPSUM</div>
<div class="child-3"> LOREN IPSUMLOREN IPSUM</div>
</div>
NOTE: The truth of the matter is, because divs #1 and #2 have the same flex-grow factor, and div #3 has a factor of 0, the value is irrelevant. You could use any number to replace 0.5. As long as it's the same in both divs, the items will compute to 225px, because the proportions will be the same.
More information:
flex-grow not sizing flex items as expected
How to get flexbox to include padding in calculations?
What are the differences between flex-basis and width?

Flex = 0.5 means, you have flex-grow = 0.5, flex-shrink = 1 and flex-basis = 0
you are allocating the available space to flex items.
Let's just say, you have a container (Assuming div element) of width: 100vw with two flexible items(div elements) of each 40vw in it. So the total width consumed by your two div elements will be equals to 80vw and the left over available space would be 20vw. Now, You have set the flex = 0.5 for each of the two div elements. so, Each div element will grow up by 20vw/2 = 10vw in order to fully occupy the free space of the container.
Consider one more scenario with 3 div elements, div1 of width = 30vw, div2 of width = 10vw and div3 of width = 25vw.
Total width consumed by 3 div elements = 30 + 10 + 25 = 65vw.
Total available space = 100 - 65 = 35vw.
Now, Each div element is set to flex = 0.3, so each will grow up by 35/3 =~ 11.66vw

Related

Force flex item to span full row width

I'm trying to retain the first 2 child elements on the same row while the third element is in its own below at full width, all while using flex.
I'm particularly interested in using the flex-grow and flex-shrink properties on the first 2 elements (which is one of my reasons for not using percentages) however the third element really must be full width and below the first two.
The label element is added programmatically after the text element when there's an error and I can't change the code.
How do I force the label element to span a 100% width below the other two elements which are positioned using flex?
.parent {
display: flex;
align-items: center;
width: 100%;
background-color: #ececec;
}
.parent * {
width: 100%;
}
.parent #text {
min-width: 75px;
flex-shrink: 2.25;
}
<div class="parent">
<input type="range" id="range">
<input type="text" id="text">
<label class="error">Error message</label>
</div>
When you want a flex item to occupy an entire row, set it to width: 100% or flex-basis: 100%, and enable wrap on the container.
The item now consumes all available space. Siblings are forced on to other rows.
.parent {
display: flex;
flex-wrap: wrap;
}
#range, #text {
flex: 1;
}
.error {
flex: 0 0 100%; /* flex-grow, flex-shrink, flex-basis */
border: 1px dashed black;
}
<div class="parent">
<input type="range" id="range">
<input type="text" id="text">
<label class="error">Error message (takes full width)</label>
</div>
More info: The initial value of the flex-wrap property is nowrap, which means that all items will line up in a row. MDN
Depends if it's
Flex-direction:row (it's by default row) / on parent container
Try using justify-self: stretch / on the child that you want full width
Flex-direction-column / on a parent container
-Try using align-self: stretch / on the child that you want full width
Hopefully will help someone in some situations, usually helps me

FlexBox - specify a certain child div to control the width? [duplicate]

This question already has answers here:
One flex/grid item sets the size limit for siblings
(6 answers)
Closed 5 years ago.
With flexbox, the childs by default resize according to the widest element.
Is there some way to define that a particular child will control the width, even if it's smaller? With selectors maybe?
Codepen: https://codepen.io/dsomekh/pen/rwEYYE
Code:
.center {
display: flex;
align-items: center;
justify-content: center;
}
.first {
border: 1px solid red;
margin-bottom: 0.5vw;
}
.second {
border: 1px solid red;
}
.wrapper {
font-family: Calibri;
display: flex;
flex-direction: column;
}
<html>
<div class="center">
<div class="wrapper">
<div class="first">This DIV is bigger. However, can it shrink according to it's brother?</div>
<div class="second">This div is smaller.Can it control the width?</div>
</div>
</div>
</html>
Here's the important CSS rule to know:
flex: {number} {number} {number};
The third number is the default size of a flex-item (width, if the flex item is in a row). By default it is auto meaning a flex-item's default size is dictated by it's content.
The first and second numbers are proportionally how much it can grow or shrink by, respectively, compared to other flex items if there is room along the main axis (again, width if this flex item is in a row).
So, you cannot set the default size of a flex-item to be relative to a sibling's intrinsic size - i.e. that which is dictated by it's content - but you can set the default size of a flex-item (and it's sibling items) to all be the same and let them grow or shrink.
I find myself often doing the following:
flex: 1 0 0
on flex items which cause siblings to all be the same size.
All flex-items start out with a default size of 0 and they all grow equally - as given by the first number being the same for all flex items (here it's a one, but it could be any positive number as long as it's the same for every sibling) - as they need to.
Best flexbox learning around is here: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
EDIT
If you knew, in advance, which item was going to be intrinsically bigger, you could probably do it by setting that item to flex: 0 0 auto and letting all other flex-item's grow from flex: 1 0 0, but I have a feeling you don't know in advance which one is bigger.
.wrapper { display: flex; }
.wrapper>div { border: 1px solid #000; }
.first { flex: 1 0 0; }
.second { flex: 0 1 auto; }
<div class="center">
<div class="wrapper">
<div class="first">This DIV is bigger. However, can it shrink according to it's brother?</div>
<div class="second">This div is smaller.Can it control the width?</div>
</div>
</div>

creating equal width flex items

I'm using flex for layout purposes, but the browser does not spread the width equally between items.
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1 1 auto;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
Now, I want the buttons to split the container length 50% / 50%.
But that's not what's happening. I tried using flex: 1 1 auto and flex: 1 1 0 but with no success.
I know that I can use the OK button directly and it will solve my problem, but in my particular scenario it's important to wrap it with a div.
Now, as I understand it, flex should be able to spread the width equally and that's my goal here.
One more thing though, I noticed that the button content seems to have an effect on the width and I want to ignore this effect somehow.
Thanks!
JSFiddle example:
https://jsfiddle.net/edismutko/cvytLkyp/3/
flex-basis: auto vs flex-basis: 0
You're sizing your flex items with flex: 1 1 auto.
However, if you want to distribute space evenly among items, you need to use flex: 1 1 0.
The difference is the flex-basis component.
With flex-basis: 0, every item is considered to have a zero width and flex-grow distributes container space equally among them. This results in all items having the same length.
With flex-basis: auto, the size of the item is factored into the flex-grow calculation and container space is distributed proportionally among items.
So when you want equal length items use flex: 1 1 0, which is the same as flex: 1.
Here's a more detailed explanation: Make flex-grow expand items based on their original size
Default rules on button elements
Browsers apply styles to elements by default. For instance, Chrome adds padding and border widths to button elements.
Reset those defaults.
Now you have two equal width flex items. (Additional styling is up to you.)
.parent {
display: flex;
width: 200px;
}
.btn1 {
flex: 1;
}
button {
padding: 1px 0;
border-left-width: 0;
border-right-width: 0;
}
<div class="parent">
<div class="btn1">
<button align="left" style="width:100%">Ok</button>
</div>
<button align="left" class="btn1">Cancel</button>
<div>
box-sizing: border-box
Something else to consider is including the padding and border lengths in the width / flex-basis calculation. Why are borders causing div to overflow container?

How to get flexbox to include padding in calculations?

Below are two rows.
First row is two items at flex 1 and one at flex 2.
Second Row is two items at flex 1.
According to the spec 1A + 1B = 2A
But when padding is included in the calculation the sum is incorrect as you can see in the example below.
QUESTION
How to get flex box to include padding into its calculation so the boxes in the example line up correctly?
.Row{
display:flex;
}
.Item{
display:flex;
flex:1;
flex-direction:column;
padding:0 10px 10px 0;
}
.Item > div{
background:#7ae;
}
.Flx2{
flex:2;
}
<div class="Row">
<div class="Item">
<div>1A</div>
</div>
<div class="Item">
<div>1B</div>
</div>
<div class="Item Flx2">
<div>1C</div>
</div>
</div>
<div class="Row">
<div class="Item">
<div>2A</div>
</div>
<div class="Item">
<div>2B</div>
</div>
</div>
The solution:
Set margin on the child element instead of padding on your flex item.
.Row{
display:flex;
}
.Item{
display:flex;
flex:1;
flex-direction:column;
}
.Item > div{
background:#7ae;
margin:0 10px 10px 0;
}
.Flx2{
flex:2;
}
<div class="Row">
<div class="Item">
<div>1A</div>
</div>
<div class="Item">
<div>1B</div>
</div>
<div class="Item Flx2">
<div>1C</div>
</div>
</div>
<div class="Row">
<div class="Item">
<div>2A</div>
</div>
<div class="Item">
<div>2B</div>
</div>
</div>
The problem:
The calculation is done without padding. So; adding padding to the flex element is not giving you your expected width by the
spec.
The specific article
For example, the available space to a flex item in a floated auto-sized flex container is:
the width of the flex container’s containing block minus the flex container’s margin, border, and padding in the horizontal dimension
infinite in the vertical dimension
Why is the padding not calculated? That's what the spec wants.
Determine the available main and cross space for the flex items. For each dimension, if that dimension of the flex container’s content box is a definite size, use that; if that dimension of the flex container is being sized under a min or max-content constraint, the available space in that dimension is that constraint; otherwise, subtract the flex container’s margin, border, and padding from the space available to the flex container in that dimension and use that value. This might result in an infinite value.
If you subtract the padding and margin from the element's size, you get:
1A + 1B = 2A
However, after you did that, the padding was added to the element. The more elements, the more padding. That's not being calculated in the width, causing your statement to be false.
How to get flexbox to include padding in calculations?
In your code, padding is included in the calculations.
According to the spec 1A + 1B = 2A
I don't believe this is correct. Maybe provide a link reference for an explanation.
The flex-grow property
When you apply flex: 1 to an element, you are using the flex shorthand property to say this:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
flex-grow tells a flex item to consume the free space in the container.
Here is your code:
.Item {
display: flex;
flex: 1;
flex-direction: column;
padding: 0 10px 10px 0;
}
In the first row, padding-right: 10px is applied to three flex items.
In the second row, padding-right: 10px is applied to two flex items.
Hence, in the first row there is 10px less free space to distribute. This breaks the grid's alignment.
For distributing space (e.g., you want an element to take the remaining height or width of a container), use flex-grow.
For precise sizing of a flex item use flex-basis, width or height.
Here's some more info:
flex-grow not sizing flex items as expected
How exactly does flex-grow work with flexbox?
Not sure I follow the accepted answer. The nested flex container doesn't seem to be relevant to the problem. If you run the example without display: flex; on .Item, the problem persists.
The problem here seems to be that flex-grow only calculates the available space that it can take after factoring in the cumulative horizontal padding.
Let's assume the top level flex container is 300px wide.
1st row's available space: 300px - 30px padding = 270px
The flex items in this row have flex-grows of 1, 1, and 2, for a total of 4 units. 270 / 4 = 67.5px. The content boxes of 1A and 1B are thus 67.5px each, the content box of 1C is 135px.
2nd row's available space: 300px - 20px padding = 280px
We have flex-grows of 1 for both 2A and 2B in this row. 280 / 2 = 140px.
So 1A and 1B would have a content box of 67.5px + 10px horizontal padding, making their total width 77.5px each.
2A would have a content box of 140px + 10px horizontal padding, making its total width 150px.
77.5px + 77.5px ≠ 150px. In other words, 1A + 1B ≠ 2A, and that's why they aren't lining up.
The accepted answer does solve the problem, but CSS grid has become well supported since that answer was submitted, and is the more idiomatic approach nowadays for this problem.
.Row{
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.Item:nth-child(n + 3) {
grid-column: span 2;
}
.Item > div{
background:#7ae;
}
<div class="Row">
<div class="Item">
<div>1A</div>
</div>
<div class="Item">
<div>1B</div>
</div>
<div class="Item">
<div>1C</div>
</div>
<div class="Item">
<div>2A</div>
</div>
<div class="Item">
<div>2B</div>
</div>
</div>
By default, when using flexbox, the padding property is not included in the calculation of the element's width or height. To include the padding in the calculation, you can set the box-sizing property to border-box.
.Row{
display:flex;
}
.Item{
display:flex;
flex:1;
flex-direction:column;
padding:0 10px 10px 0;
box-sizing: border-box; // Add this line
}
.Item > div{
background:#7ae;
}
.Flx2{
flex:2;
}
You can use floated pseudo block elements instead of padding, like this:
(In this case 30px right padding)
.Item:after {
content: '';
display: block;
float: right;
width: 30px;
height: 100%;
}

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

I'm using CSS flexbox to build a scalable, responsive grid. When applying a Google chart to one of the flexbox items, the item changes size ever so slightly. It's enough to throw the grid out of alignment. I put together the following images to help illustrate the issue.
Flexbox grid before applying Google chart to item 6:
Flexbox grid after applying Google chart to item 6:
The Flexbox grid loads faster than the Google chart, so the grid originally loads correctly. However when the chart loads, item 6 expands slightly, causing image 2 above.
The middle column flex container and item 6 div are setup in css as follows:
#middlecolumn {
width: 75%;
height: 100%;
display: flex;
flex-flow: column;
margin: 0.25%;
}
#item6_div {
flex: 3;
margin-top: 0.8vh;
}
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.
Is there something I'm missing in css to prevent the Google chart from resizing its flexbox container 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.
The following solution could be used to keep a column contain all the available space: use the grow and shrink to 0 on other columns, and flex-grow=1 to the full width column, eg (CodePen):
function update() {
var text =
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.";
document.querySelector(".three").innerHTML = text;
}
.container > div:not(.three) {
flex-grow: 0;
flex-shrink: 0;
}
.one { width: 10%; }
.two { width: 200px; }
.three { flex-grow: 1; }
.four { width: 200px; }
.five { width: 10%; }
html,
body {
margin: 0;
padding: 0;
height: 100%;
}
.container {
background: tomato;
display: flex;
height: 100%;
}
.container > div:nth-child(even) {
background-color: green;
}
.three { background: yellow; }
<div class="container">
<div class="one"> one </div>
<div class="two"> two <br />
<button onclick="update()">update</button>
</div>
<div class="three"> three </div>
<div class="four"> four </div>
<div class="five"> five </div>
</div>
I'm sure it's not the best solution but it works for me:
for example, if you have a line of four items that should spread evenly on your entire screen.
add in CSS for each of them:
min-width: 20vw;
Apply this css to the part you want to stretch:
flex: 1