Truncating text inside nested flex elements - css

I have a nested flex container whose text I want to truncate when it isn't wide enough to show (https://codepen.io/BigMike/pen/mmMxQN).
What I want
(Large Screen)
(Small Screen with truncation)
I thought I could do it with
.truncated {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
but as I shrink the screen, the child reaches a point where it won't get any smaller.
Any suggestions?

Based on your comment, if you add this rule, it will all stay on one line
.regular {
flex-shrink: 0; /* won't allow element to become smaller than its content */
}
Updated codepen
.rows {
display: flex;
flex-wrap: wrap;
}
.child {
flex-basis: 50%;
background-color: red;
min-width: 0px;
}
.nested-row {
display: flex;
padding: 20px;
background-color: blue;
justify-content: space-between;
color: white;
}
.nested-child {
border: solid white 1px;
}
.truncated {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border: solid white 1px;
min-width: 0;
}
.regular {
flex-shrink: 0;
}
<div class="rows">
<div class="child">
<div class='nested-row'>
<div class="nested-child truncated">
I want this text to truncate but it breaks on a small screen
</div>
<div class='nested-child regular'>
Now this doesn't wrap
</div>
</div>
</div>
<div class="child">
Some other content
</div>
<div class="child">
Some other content
</div>
<div class="child">
Some other content
</div>
</div>

The problem is the white space property. You can just edit your style sheet like so.
.truncated {
overflow: hidden;
text-overflow: ellipsis;
white-space: wrap;
}

Related

Remove extra horizontal width from overflow wrapping with flex

Essentially, I am trying to remove/prevent the extra horizontal width created when a horizontal row of block elements has any of the block elements wrapped. That is, I want the width of the div containing the overflow elements to be just the size of the nonwrapped elements.
The following code can be used to see the issue in question:
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="example.css">
</head>
<body>
<div class="card">
<div class="card-content">
<div>
<div class="row">
<p class="note-title">This is a relatively lengthy example title for example purposes.</p>
<div>
<div class="row">
<div class="note-tags-list">
<p id="blank-tag">.</p>
<p class="tag note-tag">crunchy</p>
<p class="tag note-tag">recipe</p>
<p class="tag note-tag">carrot</p>
</div>
<p id="text-that-should-stay">I stay</p>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
/* example.css */
#import "https://cdn.jsdelivr.net/npm/bulma#0.9.3/css/bulma.min.css";
#text-that-should-stay {
white-space: nowrap;
color: white;
}
#blank-tag {
width: 30px;
min-width: 30px;
}
.note-title {
white-space: nowrap;
color: white;
overflow: hidden;
text-overflow: ellipsis;
}
.card {
background-color: black;
}
.row {
display: flex;
justify-content: space-between;
}
.note-tag {
width: 175px;
min-width: 0px;
}
.note-tags-list {
display: flex;
flex-flow: row wrap;
overflow: hidden;
height: 24px;
justify-content: flex-end;
}
For ease, the code above can be seen in the following JSFiddle, though running the above code locally will produce the same result: https://jsfiddle.net/5L7u2gkp/1/.
Here is a gif that shows the issue and then what would be ideal visually:
SECOND EDIT
I might not get you right, but there is no extra width when you remove the blank tag.
If you are talking about the gap between node-title and note-tags-list, it derives from flex-grow: 0;, which is the default for flex items. You can add to .tag the flex-grow property as flex-grow: 1; and it will make your tags grow to the maximum space they can get.
#import "https://cdn.jsdelivr.net/npm/bulma#0.9.3/css/bulma.min.css";
#text-that-should-stay {
white-space: nowrap;
color: white;
}
.note-title {
white-space: nowrap;
color: white;
overflow: hidden;
text-overflow: ellipsis;
}
.card {
background-color: black;
}
.row {
display: flex;
justify-content: space-between;
}
.note-tag {
width: 175px;
min-width: 0px;
flex-grow: 1;
}
.note-tags-list {
display: flex;
flex-flow: row wrap;
white-space: nowrap;
overflow: hidden;
height: 24px;
justify-content: flex-end;
}
<div class="card">
<div class="card-content">
<div>
<div class="row">
<p class="note-title">This is a relatively lengthy example title for example purposes.</p>
<div>
<div class="row">
<div class="note-tags-list">
<p class="tag note-tag">crunchy</p>
<p class="tag note-tag">recipe</p>
<p class="tag note-tag">carrot</p>
</div>
<p id="text-that-should-stay">I stay</p>
</div>
</div>
</div>
</div>
</div>
</div>
EDIT - based on your comments
so actually, the excess width is coming from the `#blank-tag`. You set its width to `30px`. If you remove it / change its width to 0, it will solve your problem. Otherwise, there will always be a 30px gap.
the
"pink" width
It is not related to the width of your elements; it's how chrome devtools represent the position of your elements when you use flexbox. You can (and should!) read more here.
You can check it yourself by changing the width of the div in the devtools to 202px (as seen in the picture you added), and you'll see there will be no change in the display.
Its because of flex-flow: row wrap;
To clarify, The flex-flow wrap's the content inside .note-tags-list,When the space is not enough to display items inside it(crunchy|recipe|carrot),Vertically,The items that are placed vertically are not visible,as there is fixed height to one of its parent.
The answer is to remove flex-flow: row wrap;
See This fiddle-fork
what do you think about this answer? i only slightly changed the HTML codes.
i change the min-width of .note-tag and set a flex-grow for it.
and now ...
I want the width of the div containing the overflow elements to be just the size of the nonwrapped elements.
is working
#import "https://cdn.jsdelivr.net/npm/bulma#0.9.3/css/bulma.min.css";
#text-that-should-stay {
white-space: nowrap;
color: white;
}
.note-title {
white-space: nowrap;
color: white;
overflow: hidden;
text-overflow: ellipsis;
border: 1px dashed blue;
}
.card {
background-color: black;
}
.row {
display: flex;
justify-content: space-between;
}
.tags-list{
display: flex;
justify-content: flex-end;
border: 2px dashed green;
}
.note-tag {
min-width: 175px;
flex-grow: 1;
}
.note-tags-list {
display: flex;
flex-flow: row wrap;
gap: 5px;
overflow: hidden;
height: 24px;
justify-content: flex-end;
border: 1px dashed red;
}
<div class="card">
<div class="card-content">
<div>
<div class="row">
<p class="note-title">This is a relatively lengthy example title for example purposes.</p>
<div class="tags-list">
<div class="note-tags-list">
<p class="tag note-tag">crunchy</p>
<p class="tag note-tag">recipe</p>
<p class="tag note-tag">carrot</p>
</div>
<p id="text-that-should-stay">I stay</p>
</div>
</div>
</div>
</div>
</div>

CSS: display: flex and text ellipsis on the same element

I'm trying to get an element with display: flex to work with text-overflow: ellipsis so overflown text is truncated with .... The width of the element is defined via its flex-basis from a parent flexbox, see here:
.parent {
display: flex;
min-width: 0;
}
.child {
display: flex;
background: yellow;
flex: 0 0 5em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="parent">
<div class="child">
abcabcabcabcabcabcabc
</div>
</div>
I've search similar answers but none seem to cover this exact case. I do not want to introduce any additional elements and I want to keep the display: flex on the element because I need it for vertical centering.
As #misorude said, text-overflow applies to block container elements.
Try the following:
.parent {
display: flex;
min-width: 0;
}
.child {
display: block;
background: yellow;
flex: 0 0 5em;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="parent">
<div class="child">
abcabcabcabcabcabcabc
</div>
</div>

Text breaking out of flexbox container

I've been working on learning flexbox for layout and have been unable to figure out why text is not wrapping inside the flex-item. The text is breaking out of the container like this:
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-item {
padding: 5px;
border: 1px solid black;
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>
There are no spaces between your text.
The default value of the word-break property is normal, meaning that a continuous line of text has no line breaks.
For these reasons, your text is not wrapping and overflowing the container.
Add word-break: break-all to .flex-item.
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-item {
padding: 5px;
border: 1px solid black;
word-break: break-all; /* new */
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>
From MDN:
word-break
The word-break CSS property specifies whether or not the browser
should insert line breaks wherever the text would otherwise overflow
its content box.
In contrast to overflow-wrap, word-break will create a break at
the exact place where text would otherwise overflow its container
(even if putting an entire word on its own line would negate the need
for a break).
Values
normal
Use the default line break rule.
break-all
To prevent overflow, word breaks should be inserted between any two
characters (excluding Chinese/Japanese/Korean text).
keep-all
Word breaks should not be used for Chinese/Japanese/Korean (CJK) text.
Non-CJK text behavior is the same as for normal.
There's actually another reason – flexbox-specific – why the flex items are overflowing the container. Here's the explanation:
Why doesn't flex item shrink past content size?
To contain the items (without the need for the text to wrap), you could apply min-width: 0, overflow: hidden or overflow: auto to .flex-column.
html,
body {
height: 100%;
}
.main {
max-width: 10em;
margin: 1em auto;
}
.flex-row {
display: flex;
align-items: center;
justify-content: center;
min-height: 12em;
border: 1px solid red;
}
.flex-column {
display: flex;
flex-direction: column;
overflow: hidden; /* new */
/* overflow: auto; */
/* min-width: 0; */
}
.flex-item {
padding: 5px;
border: 1px solid black;
}
<div class="main">
<div class="flex-row">
<div class="flex-column">
<div class="flex-item">
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div class="flex-item">
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</div>
</div>
</div>

text-overflow ellipsis on flex child not working [duplicate]

This question already has answers here:
Prevent a child element from overflowing its parent in flexbox [duplicate]
(1 answer)
Why don't flex items shrink past content size?
(5 answers)
Ellipsis not working in flex container
(1 answer)
How to make a sticky footer using flexbox in IE11?
(5 answers)
Closed 5 years ago.
I have container with flex. I want the middle child will take the entire space so I set it flex: 1. So far so good.
The next level is that the middle child has 2 child so I want to set it flex too (If you lost me, just skip to the snippet) and the first child I set ellipsis styles. Now, the ellipsis stops working.
If you will click on the button, you will see that everything good with short text;
Any ideas?
function toggle() {
var el = document.querySelector('.el');
el.textContent = el.textContent === 'short' ? 'long long long text' : 'short';
}
.wrapper {
display: flex;
width: 200px;
align-content: stretch;
padding: 5px;
min-width: 0;
border: 1px solid
}
.wrapper .child2 {
flex-grow: 1;
}
.flex {
display: flex;
min-width: 0;
}
.el {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child1 {
background: red;
}
.child2 {
background: blue;
}
.child3 {
background: green;
}
.wrapper>* {
padding: 5px;
}
<div class="wrapper">
<div class="child1">child1</div>
<div class="child2">
<div class="flex">
<div class="el">long long long text</div>
<div>a</div>
</div>
</div>
<div class="child3">child3</div>
</div>
<button onclick="toggle()">Toggle ellipsis text</button>
Add overflow: hidden; to .wrapper .child2.
Actually, as Mosh Feu suggests in his answer, min-width: 0 should also work, and does, cross browser, though IE is buggy and need overflow
The reason also the child2 need it, is because it is also a flex item, and flex item's, in this case min-width, defaults to auto, and won't allow it to be smaller than its content, so by adding overflow: hidden (or any value but visible), or min-width: 0, will let it.
function toggle() {
var el = document.querySelector('.el');
el.textContent = el.textContent === 'short' ? 'long long long text' : 'short';
}
.wrapper {
display: flex;
width: 200px;
align-content: stretch;
padding: 5px;
min-width: 0;
border: 1px solid
}
.wrapper .child2 {
flex-grow: 1;
overflow: hidden;
}
.flex {
display: flex;
min-width: 0;
}
.el {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child1 {
background: red;
}
.child2 {
background: lightblue;
}
.child3 {
background: green;
}
.wrapper>* {
padding: 5px;
}
<div class="wrapper">
<div class="child1">child1</div>
<div class="child2">
<div class="flex">
<div class="el">long long long text</div>
<div>a</div>
</div>
</div>
<div class="child3">child3</div>
</div>
<button onclick="toggle()">Toggle ellipsis text</button>
Is this what you want.?
I just put overflow:hidden;text-overflow: ellipsis; to your .child2
function toggle() {
var el = document.querySelector('.el');
el.textContent = el.textContent === 'short' ? 'long long long text' : 'short';
}
.wrapper {
display: flex;
width: 200px;
align-content: stretch;
padding: 5px;
min-width: 0;
border: 1px solid
}
.wrapper .child2 {
flex-grow: 1;
}
.flex {
display: flex;
min-width: 0;
}
.el {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child1 {
background: red;
}
.child2 {
background: blue;
overflow:hidden;
text-overflow: ellipsis;
}
.child3 {
background: green;
}
.wrapper>* {
padding: 5px;
}
<div class="wrapper">
<div class="child1">child1</div>
<div class="child2">
<div class="flex">
<div class="el">long long long text</div>
<div>a</div>
</div>
</div>
<div class="child3">child3</div>
</div>
<button onclick="toggle()">Toggle ellipsis text</button>
Apparently if I set the min-width: 0 of the middle child (.child2) it magically works.
Update According #LGSon it doesn't works on IE.
function toggle() {
var el = document.querySelector('.el');
el.textContent = el.textContent === 'short' ? 'long long long text' : 'short';
}
.wrapper {
display: flex;
width: 200px;
align-content: stretch;
padding: 5px;
min-width: 0;
border: 1px solid
}
.wrapper .child2 {
flex-grow: 1;
min-width: 0;
}
.flex {
display: flex;
}
.el {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.child1 {
background: red;
}
.child2 {
background: blue;
}
.child3 {
background: green;
}
.wrapper>* {
padding: 5px;
}
<div class="wrapper">
<div class="child1">child1</div>
<div class="child2">
<div class="flex">
<div class="el">long long long text</div>
<div>a</div>
</div>
</div>
<div class="child3">child3</div>
</div>
<button onclick="toggle()">Toggle ellipsis text</button>
That's because class .el doesn't have a width set. Use the CSS below and it works well:
.el {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 3em;
}

Display table on flex item

My question is simple. Is it possible to have display: table on a flex item?
When I set it on an item, the layout doesn't work as expected - the second flex item doesn't grab the available vertical/horizontal space.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: table;
background-color: red;
}
.content > span {
display: table-cell;
vertical-align: middle;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Of course you can, but not necessarily a good solution though.
May I suggest you use flex all the way.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
display: flex;
align-items: center;
justify-content: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Side note:
A table element is special and doesn't behave as normal block or inline elements. To make it work with display: table, you need to set a height to your parent as well as to the table, like in this sample, http://jsfiddle.net/LGSon/0bzewkf4.
Still, as you can see, the table height is 200px because flex has some flaws when it comes to limit height's, so it is not display:table that breaks your flex, it is flex who is somewhat broken.
Here is another answer of mine, showing yet another workaround where flex doesn't behave: Normalizing Flexbox overflow in IE11
It's a big question why you use table in flexbox...
But you can set width to your table and inherit min-height from parent
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
display: table;
flex:1;
background-color: red;
width:100%;
min-height:inherit;
}
.content > span {
display: table-cell;
vertical-align: middle;
height: 100%;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
You should not need to use a table layout at all here. Just add align-self: center; to .content- > span {.... And make the span element become a flex item as well, by adding display:flex to the .content element. The reason why the table layout is not working for you is because vertcal-align has no effect on the alignment of flex items. So mixing a flex-layout with a table-layout by changing the display property of a flex-item seems not to be a good idea, because you are loosing the flexibility of the flex-layout.
Properties not affecting flexible boxes
Because flexible boxes use a different layout algorithm, some properties do not make sense on a flex container:
column-* properties of the multiple column module have no effect on a flex item.
float and clear have no effect on a flex item. Using float causes the display property of the element to compute to block.
vertical-align has no effect on the alignment of flex items.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: flex;
background-color: red;
}
.content > span {
flex: 1;
align-self: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Tables are row or horizontally oriented so wouldn't you get weird results if placed within a flex-column? I changed everything to a good old block, they stack very well in a column flow--vertical harmony.
.content is dead center by using: position: relative; top: 50%; and translateY(360%); for vertical and text-align: center; for horizontal. Oh and of course turning that span into a useful block.
Changed the following:
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
I changed display: table to table-row is this what you wanted?
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>

Resources