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

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.

Related

(inline/shrink/auto?)flex grandparent -> flex parent -> flex-basis (DOA)

I'm working on a custom <tab-view> with the following markup semantics:
#tab-wrapper, #slot {
display: flex;
flex-wrap: nowrap;
}
#slot {
flex: auto 1 auto;
}
.tab {
flex: 1 1 10em;
border: 1px solid gray;
}
#new {
flex: 0 0 auto;
}
<div id="tab-wrapper">
<div id="slot">
<div class="tab">test1</div>
<div class="tab">test2</div>
</div>
<span id="new">✚</span>
<div>
But what I want is something like this:
I need the flex-basis of the tabs to be 10em initially, but also allow them to shrink when more tabs are open than there is available space.
I'm not worried about overflow or anything like that, just that the #new element comes after the tabs with their preferred 10em flex basis.
I've tried flex-shrink: auto but it has the same effect as flex-shrink: 1.
flex-shrink: 0 is not an option because I want them to be able to shrink - and in this case flex-shrink: 0 makes the #new tab button go out of view completely.
Note: the tab items themselves are also custom elements and don't use any styling other than the default display: inline but that shouldn't matter here.
I'm glad you fixed your issue with width. But I think your problem was elsewhere.
div#slot has a property of flex: auto 1 auto which is not valid and ignored. div#slot is a child of a flex element div#tab-wrapper so its width is the minimum width of the content. This is why the tabs are shrinked.
Now if you replace flex: auto 1 auto by flex: 1 1 auto (flex-grow: 1) div#slot will have a width of 100% the width of div#tab-wrapper and flex: 1 1 10em will work as expected on tabs.
#tab-wrapper,
#slot {
display: flex;
flex-wrap: nowrap;
}
#slot {
/* previouly flex: auto 1 auto; */
flex: 1 1 auto;
}
.tab {
flex: 1 1 10em;
border: 1px solid gray;
}
#new {
flex: 0 0 auto;
}
<div id="tab-wrapper">
<div id="slot">
<div class="tab">test1</div>
<div class="tab">test2</div>
</div>
<span id="new">✚</span>
<div>

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

Why flexbox won't grow to its text?

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.

Flexbox item multiline text overflow

I have flex item with very long string inside, and I want it to be wraped. But it doesn't work.
I set flex 1 1 500px, for instance (flex-basis = 500px) and it should wrap the string with word wrap: break-word
But it doesn't, and only if I set width=500px, it starts to work, so the question is why flex-basis 500px doesn't work and width works?
HTML:
<div class="map-detail-wrapper">
<div class="ad-detail-text">
<span>{{ad.text}}</span>
</div>
</div>
CSS:
.map-detail-wrapper {
display: flex;
flex-wrap: wrap;
}
.ad-detail-text {
flex: 1 1 0%;
width: 500px;
line-height: 20px;
font-size: 14px;
margin: 20px;
border: black;
word-wrap: break-word;
overflow: hidden;
}
In your case you are allowing the item to shrink giving it flex: 1 1 500px which is short for:
flex-grow: 1;
flex-shrink: 1;
flex-basis: 500px;
since the content is less the 500px width and the item is allowed to shrink, it will. To fix that you can set flex: 0 0 500px
In most cases flex-basis is equivalent to width, you can read more about the differences here
For the difference between word-break: break-all and word-wrap: break-word you can read more about it here
Finnally found workaround. You can see it there https://www.w3schools.com/code/tryit.asp?filename=FFPNFOV52YNW
It enough to add
"word-break: break-all;"
and it starting to work even without "width" only with "flex-basis".
But i still wondering why
"word-wrap: break-word" works only with "width",
and to make word wrap only with flex-basis it requires "word-break: break-all;"

Flexbox grow and shrink property columns vs determined width columns for responsive grid system

Lately I've been learning flexbox and how to make my own grid system. When making grid system using floats, we determine number of columns per layout and each column's width in percentages. But when using flexbox, all the layout tutorials I saw are simply using flex-direction: row; and flex: 1
for columns, to make all of them equal size, equal gutter, centered and in one row. But when I checked flexboxgrid source code on github, they are using same principle as bootstrap 3. They have columns for different screen sizes, 12 columns and flex-grow, shrink are disabled. Instead, each column is determined in width percentages, like col-xs-1 max-width: 8.33%.
Now I'm wondering what's the difference between these two techniques and which one is more preferable. I mean determining width for each column requires a lot of counting, while using flex grow property just fulfills the whole viewport in main axis with equally sized columns and gutters.
tl;dr
They are not techniques to achieve the same result, they do different things.
Flexbox grid uses flex-basis to determine width in flex container's main axis. It does not use flex: 1; on flex items because that is equivalent to flex: 1 1 0;. Which means flex-basis would have a value of 0, and the flex items sizes would be proportional to the specified grow and shrink factor, both having a value of 1.
Example
col-xs-1 with a flex-basis of 0 specified from flex: 1; would grow as if it was col-xs-12 if it is the only child, if there is another col-xs-1 like this as a sibling, then it would grow as if it was col-xs-6 and so forth.
It is expected for every col-xs-1 to fill 1/12, (8.33333333%), of the container, which would not be the case using flex: 1;.
* {
box-sizing: border-box;
}
article {
margin-bottom: 1rem;
}
[class^="col-"],
[class*="col-"] {
flex: 0 0 auto; /* flex-grow: 0; flex-shrink: 0; flex-basis: auto; */
}
.row {
display: flex;
margin-right: -.5rem;
margin-left: -.5rem;
}
.col-xs-1 {
padding-right: .5rem;
padding-left: .5rem;
flex-basis: 8.33333333%;
}
.box-row {
min-height: 1em;
background: #007FFF;
}
article:last-of-type .col-xs-1 {
flex: 1; /* Same as flex: 1 1 0; */
}
<article class="row">
<section class="col-xs-1">
<div class="box-row"></div>
</section>
<section class="col-xs-1">
<div class="box-row"></div>
</section>
</article>
<article class="row">
<section class="col-xs-1">
<div class="box-row"></div>
</section>
<section class="col-xs-1">
<div class="box-row"></div>
</section>
</article>

Resources