Why flexbox won't grow to its text? - css

I need .child-1-2 to grow to its text, but the text overflows. When I change flex-basis of .child-1-1 from 50px to auto, it seems to work. Why is that happening?
.parent-1 {
display: flex;
}
.child-1 {
display: flex;
flex: 0 0 auto;
background: #4c72af;
}
.child-1-1 {
display: flex;
flex: 0 0 50px;
}
.child-1-2 {
display: flex;
flex: 1 0 auto;
}
.child-2 {
display: flex;
flex: 1 0 auto;
background: #f7ed7e;
}
<div class="parent-1">
<div class="child-1">
<div class="child-1-1">C1</div>
<div class="child-1-2">Some text</div>
</div>
<div class="child-2">
<div class="child-2-1">Another text</div>
</div>
</div>

In order to understand the reason why the described behavior takes place, we should know how flex-basis and flex-grow actually work and how width of flex items is calculated.
Flex-grow
From flex-grow is weird. Or is it?
If we apply display: flex; to the parent element and don't change
anything else, the child elements will be stacked horizontally, no
matter what. If there isn't enough space, they will shrink in size. If
on the other hand there is more than enough space, they won't grow,
because Flexbox wants us to define how much they should grow. So
rather than telling the browser how wide an element should be,
flex-grow determines how the remaining space is distributed amongst
the flex items and how big the share is each item receives.
Flex-basis
Width of a flex item is determined in the following order:
content
width
flex-basis (limited by max|min-width)
From The Difference Between Width and Flex Basis
If no flex-basis is specified, then the flex-basis falls back to the
item’s width property.
If no width is specified, then the flex-basis falls back to the
computed width of the item’s contents.

Related

Flexboxgrid and gap overflow issue

Im using flexboxgrid library to create easy responsive layout, I have a parent div styled like so
display: flex;
flex-wrap: wrap;
gap: 2rem;
children have flexboxgrid styling
col-xs-12 col-md-6 col-lg-4
and it works otherwise well, except when I put that 'gap: 2rem' on parent, then div's start overflowing and push last item to another row.
To illustrate problem:
How can I fix it ?
EDIT: Link to CodePen, with gap there is 2 rows, without gap 1 row.
How to keep gap, stay on 1 row ?
https://codepen.io/ShinigamiZ/pen/YzezgwE
If you want to spread them out over the whole width, don't set a flex-basis for the elements. Rather set flex-grow: 1. This means, that the elements will grow to be as big as possible.
If you want to wrap them to a new line, you need to alter your calculation for flex-basis to also incorporate the gap.
.parent {
display: flex;
flex-wrap: wrap;
gap: 2rem;
background-color: yellow;
}
.sib {
background-color: gray;
flex-grow: 1;
}
<div class='parent'>
<div class='sib'>
123
</div>
<div class='sib'>
123
</div>
<div class='sib'>
123
</div>
</div>
Column classes (col-xs-12 col-md-6 col-lg-4) means it's percentage width and that's where the issue is because the gap is not included in percentage calculation.
My take on this is to allow the columns shrink and grow but only by the amount of gap you define. With your example that would be something like:
.col-md-6 {
flex: 1 0 calc(50% - 2rem);
max-width: 50%;
}
The only issue is a slight inconsistency with columns width if there's a empty space left or if it's the only column and not fullwidth as the elements have their own original percentage width and not one reduced by gap.
https://codepen.io/Erehr/pen/jOxYadW

Understanding flex-grow and flex-shrink when using flex-basis

I'm trying to understand the following line.
flex: 0 1 50%
Now if the last value, flex basis was pixels the above would say that the item is not allowed to grow, but allowed to shrink and will be at maximum 50 pixels.
But with percentage in there instead, what are the relations. It will be maximum 50% of width, but eh, since it is not allowed to grow it will stay at 50 percent of...something
Curious what your interpretation is.
Thanks in advance, as we say in Sweden.
Percentage lengths are relative to their containing blocks.
Therefore, if the flex container has a width of 200px, and the flex items are set to flex-basis: 50%, then each item will resolve to 100px.
Of course, in flex layout, flex-basis represents the initial main size or, the size before flex-grow and flex-shrink are applied.
You have flex-grow disabled, so nothing happens there.
But you have flex-shrink enabled, so the items will shrink below 100px when necessary to prevent an overflow of the container.
In this case, because all items are set to flex-shrink: 1, they will shrink in equal proportion.
article {
display: flex;
width: 200px;
border: 1px solid black;
}
[one] > section {
flex: 0 1 50px;
}
[two] > section {
flex: 0 1 50%;
}
[three] > section {
flex: 0 0 50%;
}
/* non-essential demo styles */
section {
height: 50px;
background-color: lightgreen;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
<p>container width 200px in all cases</p>
<article one>
<section><span>50px</span></section>
<section><span>50px</span></section>
<section><span>50px</span></section>
<section><span>50px</span></section>
</article>
<hr>
<p><code>flex-shrink</code> enabled</p>
<article two>
<section><span>50%</span></section>
<section><span>50%</span></section>
<section><span>50%</span></section>
<section><span>50%</span></section>
</article>
<hr>
<p><code>flex-shrink</code> disabled</p>
<article three>
<section><span>50%</span></section>
<section><span>50%</span></section>
<section><span>50%</span></section>
<section><span>50%</span></section>
</article>
More details about percentages and flex-basis:
§ 7.2.3. The flex-basis
property
Percentage values of flex-basis are resolved against the flex item’s
containing block (i.e. its flex container); and if that containing
block’s size is indefinite, the used value for flex-basis is
content.
More details about percentage lengths in general:
Working with the CSS height property and percentage values

Stretch child to 100% width and height without changing the child's rules

When parent is display: flex;, is there a way to force it's children to stretch itself to 100% of the parent's width and height, without accessing the children's props?
i've found align-items: stretch; for vertical stretching, but can't find something for the horizontal.
"I've found align-items: stretch; for vertical stretching, but can't find something for the horizontal"
I guess you're searching for justify-content property, but it doesn't have stretch rule, it only can accept the following rules: justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
But
You can specify flex-grow: 1 for child element and it will fill all available space of the parent.
Here is the example (I have added paddings to parent element just for example, so you can see the difference between parent and child):
.wrapper {
display: flex;
width: 80%;
height: 300px;
background-color: orangered;
padding: 8px;
}
.item {
flex-grow: 1;
background-color: forestgreen;
}
<div class="wrapper">
<div class="item"></div>
<div>
is there a way to force it's children to stretch itself to 100% of the
parent's width and height, without accessing the children's props?
No, as for an i.e. flex row item (the default), its default width is auto, which make it depend/size by its content, and for it to stretch horizontal (fill the remaining space), it needs flex-grow: 1.
The same goes for flex column item, where the flex-grow: 1 will make it fill the parent's height.
i've found align-items: stretch; for vertical stretching, but can't
find something for the horizontal
When it comes to align-items and its default stretch, it affect the cross axis, and will for i.e a flex row item, stretch it to fill its parent's height, and for a flex column item it is the other way around, where it fill its parent's width.
There is no property for the main axis that does the same, as that is what the flex property is for, here as shorthand flex: <flex-grow> <flex-shrink> <flex-basis>, and since one might want different behavior for different items, it is set on the flex item (what you call the child)
Here is a flex row samples using flex-grow: 1
.parent {
display: flex;
height: 200px;
background: red;
}
.child {
flex-grow: 1;
background: blue
}
<div class='parent'>
<div class='child'></div>
</div>

Why flex container `flex: 1 0 0px` collapses on Chrome?

On Chrome I encountered Flexbox behaviour I don't understand. When a flex child which is also a flex container has flex: 1 0 0px, it collapses itself and it's contents.
Even though flex-basis is set to 0px, as far as I understand setting flex-grow to 1 (first number in flex shorthand) should make the item grow, when needed.
In my example .bottom-container has height set to 300px. That height is respected on Firefox, but collapsed to 0px on Chrome. Why?
.top-container {
display: flex;
flex-flow: column nowrap;
}
.middle-container {
flex: 1 0 0px;
display: flex;
flex-flow: column nowrap;
}
.bottom-container {
flex: 0 0 auto;
height: 300px;
}
<div class="top-container">
<div class="middle-container">
<div class="bottom-container"></div>
</div>
<div class="middle-container">
<div class="bottom-container"></div>
</div>
</div>
The problem is with the flex-basis component.
When you have flex-basis: 0, Chrome and Firefox compute to flex-basis: 0px.
However, the pixel value breaks your layout in Chrome.
Instead, for cross-browser compatibility, use this:
flex: 1 0 0%
Ok, so here's the logic.
You haven't specified a height of .top-container so it's child elements (.middle-container) cannot grow, because there is no room for them to grow into, despite having flex: 1 0 0 and, therefore, .middle-container elements will always maintain a height of 0.

Flex item width flex-direction: column and margin: 0 auto

Why doesn't flex item A take the full width of the container when it's set to margin: 0 auto?
jsfiddle
.container {
display: flex;
flex-direction: column;
}
.a {
margin: 0 auto;
border: 1px solid red;
}
.b {
border: 1px solid blue;
}
<div class="container">
<div class="a">A</div>
<div class="b">B</div>
</div>
That's how the flexbox layout algorithm works. In this case, the following applies:
Flexible Box Layout Module - 8.1. Aligning with auto margins
Auto margins on flex items have an effect very similar to auto margins in block flow:
During calculations of flex bases and flexible lengths, auto margins are treated as 0.
Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.
In your case, you are seeing the free space distributed equally on both sides of the element. Here is another point taken from the layout algorithm:
9. Flex Layout Algorithm - 9.5. Main-Axis Alignment
Distribute any remaining free space. For each flex line:
If the remaining free space is positive and at least one main-axis margin on this line is auto, distribute the free space equally among these margins. Otherwise, set all auto margins to zero.
Align the items along the main-axis per justify-content.

Resources