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

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>

Related

How to use Flex-grow with "justify-content: start" behavior [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 1 year ago.
I have a flex container like this:
.container {
display: flex;
flex-flow: row wrap;
justify-content: start;
width: 100%;
}
.item {
border: 1px solid red;
flex: 1 1 33%;
height: 100px;
}
<div class="container">
<div class="item">#1</div>
<div class="item">#2</div>
<div class="item">#3</div>
<div class="item">#4</div>
<div class="item">#5</div>
</div>
The container holds more or less divs in a row depending on the size of the screen, so I chose to use the flex shorthand with flex-grow: 1 for smooth size changes.
My problem is that I want #4 and #5 to have the same width as #1, #2 and #3 instead of taking up the whole space.
Set flex grow to 0 and basis to 33.33%
flex: 0 1 33.33%;

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.

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: how to get divs to fill up 100% of the container width without wrapping?

I'm in the process of updating an old inline-block-based grid model I have to a newer Flexbox one I created. Everything has worked fine, apart from one little snag, which has become a bit of a dealbreaker:
I have a bunch of CSS-controlled sliders; so there's a containing wrapper with 100% width, and inside is another div: its width is also 100%, but its white-space is set to nowrap. Using inline-block, this meant that the internal divs (which were also set to 100% width) wouldn't be bound by their parents' constraints and wrap onto the next line - they'd just carry on flowing out of the box. This is exactly what I wanted. However, I cannot get this to work at all with flexbox. For reference, here's an image:
And for reference, here's a jsFiddle of the thing working with inline-block: http://jsfiddle.net/5zzvqx4b/
...and not working with Flexbox: http://jsfiddle.net/5zzvqx4b/1/
I've tried all kinds of variations with flex, flex-basis, flex-wrap, flex-grow, etc. but for the life of me I can't get this to work.
Note that I can force it to do what I want in a hacky, inflexible way by setting the .boxcontainer width to 200%. That works for this single example, but in some cases I won't know beforehand how many child boxes there will be, and I'd rather not resort to inline styling on each element if possible.
To prevent the flex items from shrinking, set the flex shrink factor to 0:
The flex shrink factor determines how much the flex item will
shrink relative to the rest of the flex items in the flex
container when negative free space is distributed. When omitted, it is
set to 1.
.boxcontainer .box {
flex-shrink: 0;
}
* {
box-sizing: border-box;
}
.wrapper {
width: 200px;
background-color: #EEEEEE;
border: 2px solid #DDDDDD;
padding: 1rem;
}
.boxcontainer {
position: relative;
left: 0;
border: 2px solid #BDC3C7;
transition: all 0.4s ease;
display: flex;
}
.boxcontainer .box {
width: 100%;
padding: 1rem;
flex-shrink: 0;
}
.boxcontainer .box:first-child {
background-color: #F47983;
}
.boxcontainer .box:nth-child(2) {
background-color: #FABCC1;
}
#slidetrigger:checked ~ .wrapper .boxcontainer {
left: -100%;
}
#overflowtrigger:checked ~ .wrapper {
overflow: hidden;
}
<input type="checkbox" id="overflowtrigger" />
<label for="overflowtrigger">Hide overflow</label><br />
<input type="checkbox" id="slidetrigger" />
<label for="slidetrigger">Slide!</label>
<div class="wrapper">
<div class="boxcontainer">
<div class="box">
First bunch of content.
</div>
<div class="box">
Second load of content.
</div>
</div>
</div>
You can use the shorthand flex property and set it to
flex: 0 0 100%;
That's flex-grow, flex-shrink, and flex-basis in one line. Flex shrink was described above, flex grow is the opposite, and flex basis is the size of the container.
In my case, just using flex-shrink: 0 didn't work. But adding flex-grow: 1 to it worked.
.item {
flex-shrink: 0;
flex-grow: 1;
}
Set the flex-direction: column
You're trying to stack the items in a column rather than a row.
{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

Fill remaining horizontal space (or max-width) AND wrap on min-width

#fit and #wrap illustrate two different behaviors that I want to have for one element depending on the situation. The element should work like #fit if there is room, but should work like #wrap if there is not enough room.
http://jsfiddle.net/benstenson/dN8VJ/
<div id="print">
Printable
</div>
<div id="fit">
Looks good on same line
</div>
<div id="wrap">
Looks good on new line
</div>
css
body{overflow:hidden;padding:1em;}
div
{
/*display:inline-block;*/
float:left;
height:1in;
margin:.5em;text-align:center;line-height:1in;
white-space:nowrap;box-shadow:0 0 .5em gray;
}
#print
{
width:5in;
background-color:black; color:white;
}
#fit
{
/* when on same line
Size to min-width
OR fill remaining space
(like flexible box style).
Either way is fine.
*/
min-width:3in;
background-color:gold;
}
#wrap
{
/* when wrapped to next line */
/* fill 100% OR to max width */
width:100%;
min-width:3in;
max-width:5in;
background-color:orange;
}
What you're looking for is Flexbox, but most browsers that support Flexbox don't support wrapping. The ones that do are IE10, Chrome, and Opera.
http://codepen.io/cimmanon/pen/lqrGB
<div class="container">
<div id="print">
Printable
</div>
<div id="either">
Looks good on either line
</div>
</div>
.container {
display: -ms-flexbox;
display: -webkit-flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
#supports (flex-wrap: wrap) {
.container {
display: flex;
}
}
.container div {
height: 1in;
margin: .5em;
text-align: center;
line-height: 1in;
white-space: nowrap;
box-shadow: 0 0 .5em gray;
}
#print {
/*-webkit-flex: 1 5in;
-ms-flex: 1 5in;
flex: 1 5in;*/
width: 5in;
background-color: black;
color: white;
}
#either {
-webkit-flex: 1 3in;
-ms-flex: 1 3in;
flex: 1 3in;
max-width: 5in;
background-color: gold;
}
Assuming I've understood your question correctly, I think you can achieve what you want with inline-block.
You'll need to put your content in a paragraph inside another div, like this:
<div class="wrap-or-fit">
<p>This is where your content goes.</p>
</div>
Then just set the min-width and max-width properties on the paragraph, as well as display:inline-block.
.wrap-or-fit > p {
max-width:5in;
min-width:3in;
display:inline-block;
...
}
If the content fits on a single line less than 3 inches wide, the container will expand to be at least 3 inches. If the content is wider than 5 inches, it is forced to wrap within a container of exactly 5 inches.
If the content is between 3 and 5 inches, the container width matches the content width. I'm not sure if that is what you wanted, but that may be the best you can do.
You can see an expanded example showing both narrow and wide content samples, and styling that more closely matching your original example in this codepen.

Resources