flexbox: break long text until sibling fits in container [duplicate] - html

This question already has answers here:
Word-wrap in flexbox is not respecting 100% width limit [duplicate]
(2 answers)
Why don't flex items shrink past content size?
(5 answers)
Closed 4 years ago.
I have two flex children. I don't know the size of those children, but I want the .right (which contains unknown, but finite number of e.g. status icons) to not break, and fit on line, while .left child (which contains label of potentially too-long text) to break so that the .right child fits.
In the snippet, the .left should break the text so that the .right fits. Neither of the two children should overflow the .container.
I'm able to accomplish this by using word-break: break-word on .left, but that's non-standard. I can also use word-break: break-all, but that doesn't try to wrap the word on next line (as word-wrap does), first, which is undesirable. word-wrap: break-word doesn't do anything.
As stated, I cannot use width: calc( 100% - <right-width> ) on .left, because I don't know width of .right child.
note: the children's height: 20px is just to see the parent container. It's not part of the requirement.
Bonus: in the example the width of .container is known, but it may potentially not be known, either (i.e. it may inherit it in some way).
.container {
display: flex;
width: 200px;
height: 40px;
background: pink;
}
.left {
background: rgba(0,255,0,.1);
height: 20px;
// word-break: break-word; // works in WebKit, but non-standard
word-wrap: break-word;
}
.right {
background: rgba(0,0,255,.1);
height: 20px;
}
<div class="container">
<div class="left">xoxoxoxoxoxoxoxoxoxoxoxoxoxoxox</div>
<div class="right">rarararara</div>
</div>

the min-width: 0 on left ensures the element doesn't auto-resize to the parent flex container, and wraps as needed. It can be substituted with overflow: hidden, which has same effect.
If left to auto (default min-width flex value), it would overflow the container if it got too big. (thanks #Michael_B)
flex: 1 (shorthand for flex: 1 0 0, or flex-grow: 1; flex-shrink: 0; flex-basis: 0) ensures the left grows and pushes the right element to the right (thanks #LGSon)
right has initial flex values (flex: 0 1 auto) which ensures it doesn't word-break and doesn't grow above its content size, either.
WTBS, if it gets too big, it will also need word-wrap: break-word; min-width: 0 same as left.
Note: removed the 20px height which was not part of the OP requirement.
.container {
display: flex;
width: 200px;
background: pink;
}
.left {
background: rgba(0,255,0,.1);
word-wrap: break-word;
min-width: 0;
flex: 1;
}
.right {
background: rgba(0,0,255,.1);
}
<div class="container">
<div class="left">aaaaaaaa bbbbbbbbbbbbbbbbbbbb</div>
<div class="right">cccccc ccccc</div>
</div>

Related

Container does not shrink when inner text wraps

I am trying to have two elements horizontally aligned where the one on the left has text that may wrap then sizing the screen, and the one on the right allows for no wrapping. When the content wraps, the first element maintains the width of content + (wrapped word - pixels causing wrapping), instead of shrinking to fit the content.
I created an example on Fiddle where you can see the grey background of the first element having no content for a couple of pixels, instead of resizing to only include the text.
.container {
display: flex;
width: 760px;
}
.item {
background-color: grey;
width: fit-content;
block-size: fit-content;
}
.item2 {
background-color: green;
white-space: nowrap;
align-self: flex-start;
}
<div class="container">
<div class="item"><span> This Text to auto-adjust to only fit the content when wrapping</span></div>
<div class="item2">This should be right next to last word on first line on the left</div>
</div>
JSFiddle Demo
Is there a way of achieving an auto-size to only fit-content on resizing of the screen so the 2 element stays as close to the text of the first one as possible?
Elements inside a flexbox has flex-grow and flex-shrink set by default, which allows them to bypass the basic width and height properties.
To solve this problem, just disable flex-grow and flex-shrink:
.item {
background-color: grey;
width: fit-content;
block-size: fit-content;
flex-grow: 0;
flex-shrink: 0;
}

While using flex (column) for parent, Auto margin shrinks the child div [duplicate]

This question already has answers here:
How can I center text (horizontally and vertically) inside a div block?
(27 answers)
Closed 2 years ago.
I am trying to horizontally center one div inside parent div (Which is display flex in column mode) using margin 0 auto. When I do this the inner div is getting shrinked to the size of its content. Can someone explain why this is happening and how to fix this?
HTML
<div class="container">
<div class="mydiv">
CENTER THIS DIV
</div>
</div>
CSS
.container{
background-color: brown;
height: 100px;
display: flex;
flex-direction: column;
}
.mydiv{
background-color: chartreuse;
max-width: 500px;
margin: 0 auto;
}
If I remove flex from parent, then I am getting the correct output :
However, with the flex properties as in above code, this is what I get :
When you use display: flex; in a parent, the children automatically get the default flex values:
The item is sized according to its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container. This is equivalent to setting "flex: 0 1 auto".
That's why your .mydiv adjusts to fit the text.
(more info: https://developer.mozilla.org/en-US/docs/Web/CSS/flex)
If you don't want that to happen you could do something like this:
.container{
background-color: brown;
height: 100px;
display: flex;
flex-direction: column;
align-items: center; /* add this */
}
.mydiv{
background-color: chartreuse;
width: 100%; /* add this */
max-width: 500px; /* add this */
}
Working example:
https://codepen.io/sergiofruto/pen/dyMqbrm

Flex Basis behavior not as expected but max-width works

I actually found a solution to my problem but would like to know why my original solution doesn't work.
I have a simple flex container in which I want the first div to be 30% of the container. I gave it a flex-basis of 30% to try to achieve this. This works until I have content that exceeds the length of 30%. At this point, it extends the div making it more than 30%.
I solved this using the max-width attribute which I found from another question after some research, but am still confused why flex-basis does not work, and would prefer not to have a max-width attribute when using flex box. I read that if flex-direction is row, flex-basis should be a replacement for width, but this does not seem to be the case.
Here is a fiddle and the css along with it:
https://jsfiddle.net/jg5nbdgp/12/
.container {
display:flex;
flex-direction: row;
.left {
flex-basis: 30%; /* This doesn't work */
/* max-width: 30%; */ /* This works */
.box {
height: 50px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.middle {
flex-basis: 50%;
}
.right {
flex-basis: 20%;
}
}
It is because flex box items cannot be smaller than the actual content. This is the default behaviour of flexbox.
Including min-width:0 to .left class will make flex-basis work.
So in your case your content width is greater the flex-basis value and by the default flexbox behaviour flex box width cannot be smaller than the content. By flexbox terms your code has actually become
.left {
flex-basis: 30%;
min-width: auto;
max-width: auto;
}
so you have to update the width to let flexbox come over the default behaviour. update your class to
.left {
flex-basis: 30%;
min-width: 0;
}
In order words you can remember width values precedes the flex-basis values.
JsFiddle: https://jsfiddle.net/gLodw7k1/
I had a similar issue. I had 2 equal columns with a max width like so:
flex-basis: 50%;
max-width: 30em;
Worked everywhere but IE. In IE it would shrink the columns. I fixed it by changing basis to the same value like so:
flex-basis: 30em;
max-width: 30em;
It's still responsive, because flex-basis works with proportions, so for 2 children it's equivalent to 50%.

Flexbox align-items overflow text get cuts off at top [duplicate]

This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
How to use safe center with flexbox?
(3 answers)
Closed 5 years ago.
I have the following situation, the text get cuts off at the top when it not longer fits inside the container. What can I do to fix that? I'd still like the text to be centered if it's smaller than the container, and I can't change the container size.
div {
display: flex;
align-items: center;
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
}
<div>
sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd
</div>
The problem here is caused by the fact that when using align-items (or justify-content) to center a flex row item, it will, by design, overflow at its top/bottom (or left/right).
To solve that a new keyword, safe, is introduced, though not many browsers support it yet.
How to use safe center with flexbox?
The other option is to use auto margin's, though with the given markup you can't, as the text doesn't have an inner wrapper (well, it has an anonymous one, though those we can't target with a CSS selector).
So by adding an inner wrapper (fiddle with wrapper) you can use auto margin's, and is well explained here:
Can't scroll to top of flex item that is overflowing container
But sometimes we just can't change the markup, and when, here is a little trick, using the pseudo elements, and use auto margin's on them.
To vertical center the text we also need the flex direction to be column so the pseudo is rendered above/below.
Stack snippet
div {
display: flex;
flex-direction: column; /* added */
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
border: 1px solid gray;
}
div::before, div::after {
content: '';
}
div::before {
margin-top: auto; /* added */
}
div::after {
margin-bottom: auto; /* added */
}
<div>
sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd
</div>
<div>
sdjhf
</div>
If you wrap the text into another tag, and set margin: auto 0; it seems to be working well.
div {
display: flex;
width: 100px;
height: 50px;
overflow: auto;
word-break: break-word;
background: pink;
margin-bottom: 20px;
}
span {
margin: auto 0;
}
<div>
<span>sdjhfkahsdkjfadsfhk jaskjfsj fsldflkasjklsjflakj flksjfakljflksjflkasfjklasjflfd</span>
</div>
<div>
<span>sdjhfkah</span>
</div>

Make flex item have 100% height and overflow: scroll [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 5 years ago.
I want a flex item to take 100% of remaining height and display the overflow: scroll bar.
It looks like problem comes from my #userList which takes 100% of the window height and not taking the remaining space .
body {
display: flex;
flex-direction: column;
min-height: 100%;
margin:0px;
}
.wrapper {
display: block;
flex: 1 1 auto;
display: flex;
flex-direction: row; /
}
#chatContainer {
background: orange;
width: calc(100% - 350px);
display: flex;
flex-direction: column;
}
#tabs{
background-color: red;
flex: 1 1 0px;
display: flex;
}
#usersContainer {
flex: 1 1 0;
display:flex;
flex-direction:column;
}
#userListWrapper {
background-color:pink;
flex: 1 1 auto;
display:flex;
}
#userList {
-webkit-flex: 1 1 auto;
overflow: auto;
min-height: 0px;
height:100%;
}
.input {
background-color: #49FFFC;
}
<div class="wrapper">
<div id="chatContainer">
<div id="webcamContainer">webcam</div>
<div id="tabs">tabs here</div>
<div id="footer" style="background-color:#A0C8FF;height:50px">footer</div>
</div>
<div id="usersContainer" style="background-color:blue">
<div class="input">searchInput1</div>
<div class="input">searchInput2</div>
<div id="userList">
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>user1<br>user2<br>
</div>
</div>
</div>
https://jsfiddle.net/jpo31gq9/
The main problem you are having is a violation of the rules governing percentage heights in CSS.
Basically, when using percentage heights, you must always specify the height of the parent element. Otherwise, the element with a percentage height has no frame of reference, and the height computes to auto (the height of the content).
From the spec:
CSS height property
percentage Specifies a percentage height. The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly and this element is not absolutely positioned, the value computes to "auto".
auto The height depends on the values of other properties.
source: https://www.w3.org/TR/CSS21/visudet.html#propdef-height
So if you plan to use percentage heights, you need to specify a height on every parent element up to the root element (html) or up to a fixed height declaration (such as height: 250px).
In your CSS, you have body { min-height: 100%; }. However, there is no height specified on the parent (html).
The following parent elements in your code are missing a height declaration:
html
body (min-height doesn't count)
.wrapper
#chatContainer
With the following adjustments your layout works.
html { height: 100%; } /* NEW */
body {
display: flex;
flex-direction: column;
/* min-height: 100%; */
margin: 0px;
height: 100%; /* NEW */
}
.wrapper {
display: block;
flex: 1 1 auto;
display: flex;
flex-direction: row;
height: 100%; /* NEW */
}
#chatContainer {
background: orange;
width: calc(100% - 350px);
display: flex;
flex-direction: column;
height: 100%; /* NEW */
}
Revised Fiddle
It's also worth mentioning some variations among current browsers.
Percentage Heights: Chrome/Safari vs Firefox/IE
Although the traditional implementation of percentage heights uses the value of the height property, recently some browsers have broadened their scope.
As evidenced in the following posts, Firefox and IE are now also using flex heights to resolve the percentage height of child elements.
Chrome / Safari not filling 100% height of flex parent
Height is not correct in flexbox items in Chrome
Flexbox in Chrome--How to limit size of nested elements?
Chrome ignoring flex-basis in column layout
Bottom line: Chrome and Safari resolve percentage heights based on the value of the parent's height property. Firefox and IE11/Edge use the parent's computed flex height.
For now, the simplest cross-browser solution to this problem would be, in my view, using the height property across the board for percentage heights.