How does inline-flex container decide when text is wrapped? [duplicate] - html

This question already has an answer here:
Understanding how width of scrollbar is computed in nested flex container
(1 answer)
Closed last year.
I have an issue with text clipping where flex items are clipped too early even though their flex-basis is set to 0 so I would expect the flex container to stretch all items to be at least as big as the biggest item in the container. Anyway here's a fiddle:
https://jsfiddle.net/nxbwufLk/
How is it choosing to wrap the text? Why is it not stretching the first item.
.button {
flex: 1 1 0;
border: 1px solid red;
}
.container {
display: inline-flex;
}
<div class="container">
<div class="button">
Some text
</div>
<div class="button">
Some text that is very long indeed
</div>
</div>
I can see that the second text is wrapped but how is that decided? There are no widths set anywhere

I can see that the second text is wrapped but how is that decided? There are no widths set anywhere
There is a width set it's just not trivial to notice, You're using inline-flex which on it's own should tell you what's going on.
The width of the container will equal it's content, in this case the width of the text of both elements.
Demo
.button {
border: 1px solid red;
}
.container {
display: inline-flex;
}
.test>.button {
flex: 1 1 0;
}
No flex properties set
<br/>
<div class="container">
<div class="button">
Some text
</div>
<div class="button">
Some text that is very long indeed
</div>
</div>
<br/>
<br/>
<br/> flex properties set
<br/>
<div class="container test">
<div class="button">
Some text
</div>
<div class="button">
Some text that is very long indeed
</div>
</div>
As you can see the width of the containers is the same.
Now regardless of what we do, the width of the container is set and won't change, so when you apply flex: 1 1 0; you're simply dividing that width (evenly flex-basis:0;) between the two elements and then you get the wrapping.

Related

How the width of a inline-flex div is decided?

for an inline-flex div, the width is depending on its children elements' width. Here is the code, I don't set the parent div with specified width. So, it is decieded by inside elements.
For the three children elements, one is with width:50%, others are width:50px, but the final width for 2 is 31.75, how does it come?
<div style="display: inline-flex;flex-wrap: nowrap;">
<div style="width:50%;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
Here is a step by step illustration to understand what the browser is doing:
div div {
outline:1px solid green
}
<p>The browser will first ignore the width:50% and use auto instead</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:auto;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
<p>Now that we have the width of the parent, it will no more change and we resolve width:50%</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:50%;color:red">1</div>
<div style="width:50px;color:blue">2</div>
<div style="width:50px;color:black">3</div>
<span>hello</span>
</div>
<p>all the div will shrink because there is not enough space for them (50% + 50px + 50px + hello > 100%). A shrink that you can disable if you use flex-shrink:0 and you will have overflow</p>
<p>Only "hello" will not shrink because a flex item cannot shrink past its content size</p>
<div style="display: inline-flex;flex-wrap: nowrap;border:2px solid red">
<div style="width:50%;color:red;flex-shrink:0;">1</div>
<div style="width:50px;color:blue;flex-shrink:0;">2</div>
<div style="width:50px;color:black;flex-shrink:0;">3</div>
<span>hello</span>
</div>
For more detail about the shrink algorithm if you want to understand the calculation:
How flexbox calculates flex-item's width if no flex-basis or width are set?
Why is a flex item limited to parent size?
To understand why "hello" will not shrink:
Why don't flex items shrink past content size?
The purple area you see in the dev tools is the width before the shrink effect. You can notice it's equal to 50px for the 2nd and 3rd div

Width of vertically aligning inline-flexbox grows with number of children [duplicate]

This question already has answers here:
Make container shrink-to-fit child elements as they wrap
(4 answers)
CSS when inline-block elements line-break, parent wrapper does not fit new width
(2 answers)
Closed 4 years ago.
I want to visualize source-code-like structures in HTML using some sort of "block" analogy. But for whatever reason I walk into some strange sizing issues with my flexboxes. The following snippet displays a visualisation of a program that would "normally" be printed like this:
while(true) {
goForward();
goForward();
goForward();
goForward();
goForward();
}
The outer box for the while is displayed as inline-flex to consume as little horizontal space as possible. But as you can see in the screenshot (or you may run the snippet yourself) there is quite a lot space wasted:
What I expect would look like this:
If you however click the goForward() blocks (which marks them with display: none), the width of the parenting block suddenly shrinks. From what I can tell it shrinks about as much as the width of the now hidden block.
The "linebreaks" between goForward() blocks are implemented using height: 0 but width: 100% elements. I also tried to do the breaks without empty elements and break-after: always, but this leads to the exact some behavior of the outer flexbox. I have observed this behavior in the most recent versions of Firefox and Chrome.
Why does the width of the outermost inline-flex element change (seemingly) with the number of items it displays vertically? And how could I "properly" implement this kind of layout where I basically want to have a block layout with arbitrary "linebreaks"?
// Hide blocks on click to demonstrate width changes
Array.from(document.querySelectorAll(".forward")).forEach(
elem => elem.addEventListener('click', () => elem.classList.add("hide"))
);
.code-block {
border: 2px solid blue;
border-radius: 5px;
padding: 5px;
display: inline-flex;
flex-flow: row wrap;
align-items: baseline;
}
.line-break {
width: 100%;
}
.forward {
cursor: pointer;
}
.hide {
display: none;
}
<div class="code-block">
<div class="terminal">while(</div>
<div class="code-block">true</div>
<div class="terminal">)</div>
<div class="line-break"></div>
<div class="code-block forward">
<div class="terminal">goForward()</div>
</div>
<div class="line-break"></div>
<div class="code-block forward">
<div class="terminal">goForward()</div>
</div>
<div class="line-break"></div>
<div class="code-block forward">
<div class="terminal">goForward()</div>
</div>
<div class="line-break"></div>
<div class="code-block forward">
<div class="terminal">goForward()</div>
</div>
<div class="line-break"></div>
<div class="code-block forward">
<div class="terminal">goForward()</div>
</div>
</div>
Instead of flex-flow: row wrap;, try flex-direction: column;. This gets each item to go vertically. Then wrap everything you want to be in a single "line" in its own inside of .code-block, to keep the contents of each line together. So,
<div class="code-block">
<div class="line-break">
<div class="terminal">while(</div>
<div class="code-block">true</div>
<div class="terminal">)</div>
</div>
...and so on for the others.
(You shouldn't need align-items: baseline; either.)

Placing two divs next to each other, which should fill up the space, when both divs are of unknown width

Consider the following HTML markup:
<div class='wrapper'>
<div class='left'> Text text text </div>
<div class='right'>
<button></button>
</div>
</div>
Let's say that the button is of variable width (because of the text that appears on it). Is it possible in plain css, to place the .left and .right div next to each other, and the .left div should take up the space remaining after the width of the button element was calculated?
You can use flexbox.
flex: <positive-number>
Makes the flex item flexible and sets the flex basis to zero,
resulting in an item that receives the specified proportion of the
free space in the flex container. If all items in the flex container
use this pattern, their sizes will be proportional to the specified
flex factor.Equivalent to flex: 1 0.
Source
.wrapper {
display: flex;
}
.left {
flex: 1 1;
}
<div class='wrapper'>
<div class='left'> Text text text </div>
<div class='right'>
<button>button</button>
</div>
</div>
Change the position:relative; of #right to position:absolute;top:0;right:0; .
Alternatively you can put the right div before left div.
<div class='wrapper'>
<div id='right'> Text text text </div>
<div id='left'>
<button></button>
</div>
</div>
The elements are drawn in order. The right is drawn before and the left is drawn around the right element which will position the elements accordingly.
flexbox is another good option indeed!

Why does this behave the way it does with max-width: 0?

See http://jsfiddle.net/mpx7os95/14/
The behavior is the desired behavior, which allows the center column in a 3 column layout to take up all the space available AND still allow the text inside of it to overflow into ellipsis when shrunk far enough. This seems to work due to max-width: 0, but why does it produce this effect?
What's so special about max-width: 0 in this case?
.row {
width: 100%;
display: table;
}
.col {
position: relative;
min-height: 1px;
border: 1px #000 solid;
display: table-cell;
}
.x {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:100%;
max-width: 0;
}
<div class="row">
<div class="col">abc</div>
<div class="col x">test blah blah blah blah blah zzzzz.</div>
<div class="col">def</div>
</div>
Note: It's not just max-width:0, it's any width less than the text content's width.
The mixture of display: table-cell, max-width, and width:100% make an interesting situation that the specifications don't explicitly cover. However, by making some observations and thinking, we can understand why we have the same behavior across all major browsers.
max-width:0 tries to make the element width 0, of course, meaning that everything should be overflow. However, the combination of display: table-cell and width:100%, as seen in the linked demo, override that command for the div (maybe for the same reason why max-width does not apply to table rows) for the most part. As such, the element displays itself like it would without the max-width:0 until the width of the div is no longer large enough to contain all of the text content.
A thing to note before we continue is that the text itself by default has a width that is set by the characters inside of it. It's kind of a child element of the parent div, though there are no tags.
This innate width of the text content is the reason why max-width:0 is needed to create the effect. Once the width of the div is no longer large enough to contain all of the content, the max-width:0 property enables the width to become less than the width of the text content, but forces the text that can no longer fit to become overflow of the div itself. Thus, since the div now has text overflow and text-overflow: ellipsis is set, the text overflow is ellipsed (if that's a word).
This is very useful to us because otherwise we couldn't make this effect without a lot of messy JavaScript. Use case demo
Note: This answer describes the behavior and gives some insight as to why this is the case. It doesn't cover how display:table-cell overrides part of the max-width's effect.
This is not to be a complete answer, but a contribution.
What's so special about max-width: 0 in this case?
I'm not sure, but the cell seems to give another chance to adjust. (maybe this, algorithm point 2)
According to my experiments applies only replaced elements with intrinsic width. In this case the text block has intrinsic width by white-space: nowrap.
Items without intrinsic width fit well without using max-width: 0.
http://jsfiddle.net/rnrlabs/p3dgs19m/
* {
box-sizing: border-box;
}
.table {
display: table;
width: 300px;
}
.row {
width: 100%;
display: table-row;
}
.col {
border: 1px #000 solid;
display: table-cell;
}
.a {
min-width: 80px;
}
.x {
background: #0cf;
overflow: hidden;
text-overflow: ellipsis;
width:100%;
}
.y {
max-width: 0;
}
.z {
white-space: nowrap;
}
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x">
<img src="http://placehold.it/500x50&text=InlineReplacedIntrinsicWidth" />
</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x y">
<img src="http://placehold.it/500x50&text=InlineReplacedIntrinsicWidthPlusMaxWidth" />
</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x z">Intrinsic Width due white-space property set to nowap.</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x y z">Intrinsic Width due white-space property set to nowap and Max-Width</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x"><span>IntrinsicWidthduenospacesintextandblahIntrinsicWidthduenospacesintextandblah</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x y"><span>IntrinsicWidthduenospacesintextandMaxWidth</div>
<div class="col">end</div>
</div>
</div>
<div class="table">
<div class="row">
<div class="col">abc</div>
<div class="col x y">Non Intrinsic Width. Inline, non-replaced elements. <strong> Inline, non-replaced elements. </strong> Inline, non-replaced elements.</div>
<div class="col">end</div>
</div>
</div>
I think BoltClock's comment on Zach Saucier's answer - that the behaviour is undefined - is a good reason to avoid relying on the fact that today's browsers happen to exhibit the desired behaviour.
Many people (like me) will arrive at this question not because they have an academic interest in what max-width: 0 means in this case, but because they want to know whether it's OK to use that hack to get the ellipsis to show for text in a table cell, and FWIW I think the answer is: "not really".
A better way to get the ellipsis to work in that case is to use "table-layout: fixed" on the <table> element, as suggested in this answer.

Achieve table cell effect with floated divs

If I try to apply min-width, max-width to a floating div so that it expands to max-width when the right content is hidden does not work.
But, if I use table and 2 tds in it, the left td will expand to 100% if the right td is hidden.
Can I achieve this table effect with floated divs?
I don't think you can do what you are asking, but you can make it look like what you are asking.
Make it into two tds and put a max-width on a div inside the td. Would that work?
This isn't going to work with floats. Luckily we now have more tools at our disposal.
Here are two very simple methods to expand a div to 100% of the available width if a sibling horizontally to it is hidden or removed.
#1 – Using display: flex
Compatibility: Edge and all modern browsers. IE 10 and 11 support the non-standard -ms-flexbox.
The Basic Markup
<div class="container">
<div>
First Column
</div>
<div>
This second column can be hidden or not exist and the first column will take up its space
</div>
</div>
The CSS
The container div is given display: flex.
The containers children are give flex: 1 and they will be assigned equal width, can grow and can shrink.
.container {
width: 500px;
display: flex;
}
.container>div {
flex: 1;
background: #FF6961;
height: 200px;
margin-bottom: 20px;
}
.container>div:nth-child(even) {
background: #006961;
}
<div class="container">
<div>
Content
</div>
<div>
Content
</div>
</div>
<div class="container">
<div>
Content takes up the whole width when other divs are hidden.
</div>
<div style="display: none">
Content
</div>
</div>
<div class="container">
<div>
Content takes up the whole width when there is no other div.
</div>
</div>
Read this guide to flexbox
Read more about flexbox on the MDN
#2 – Using display: table
Compatibility: IE8+ and all modern browsers
The Basic Markup
<div class="container">
<div>
First Column
</div>
<div>
This second column can be hidden or not exist and the first column will take up its space
</div>
</div>
The CSS
The container is given display: table
The containers children are given display: table-cell and will act the same as cells in an HTML table. If a cell is hidden or is removed the other cell will take its space.
.container{
display: table;
width: 600px;
margin: 20px;
}
.container>div {
display: table-cell;
height: 200px;
background: #FF6961;
}
.container>div:nth-child(even) {
background: #006961;
}
<div class="container">
<div>
Content
</div>
<div>
Content
</div>
</div>
<div class="container">
<div>
Content takes up the whole width when other divs are hidden.
</div>
<div style="display: none">
Content
</div>
</div>
<div class="container">
<div>
Content takes up the whole width when there is no other div.
</div>
</div>
<div class="container">
<div>
Content takes up the remaining width if a cell has a fixed width.
</div>
<div style="width: 200px">
Content
</div>
</div>
Read more about CSS tables on the MDN