Situation: you have a single line of text in a flex child element. You don’t want that text to wrap, you want it truncated with ellipsis (or fall back to just hiding the overflow). But the worst happens. The unthinkable! The layout breaks and forces the entire flex parent element too wide. Flexbox is supposed to be helping make layout easier!
Fortunately, there is a (standardized) solution. You just need to use a non-flexbox property/value to do it.
What we want
The potential problem
Not only might this prevent the narrowing of a container, it might blow a container out super wide.
Child elements (of the flex child) are the issue
Confusing things a bit… if the text at hand is directly within the flex child, things work fine:
<div class="flex-parent">
<div class="flex-child">
Text to truncate here.
</div>
<div class="flex-child">
Other stuff.
</div>
</div>
/* Text is directly within flex child,
so doing the wrapping here */
.flex-child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
The problem comes up when there are child elements, like:
<div class="flex-parent">
<div class="flex-child">
<h2>Text to truncate here.</h2>
</div>
<div class="flex-child">
Other stuff.
</div>
</div>
/* Text is a header now,
so need to truncate there for it to work */
.flex-child > h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
min-width: 0;
on the flex child
The solution is Or min-width
some actual value. Without this, the flex child containing the other text elements won’t narrow past the “implied width” of those text elements.
When I first ran into this problem, I found the solution via a Pen by AJ Foster. He writes:
According to a draft spec, the above text should not fully collapse when the flex container is resized down. Because .subtitle has a width of 100%, the min-width: auto calculation that flexbox makes says that its container should be larger than we want.
I found this behavior consistent across Chrome, Opera, and Firefox. Safari was shrinking/truncating even without the min-width (against spec, I think).
Demo
See the Pen Thing you gotta know about flexbox by Chris Coyier (@chriscoyier) on CodePen.
- Works: Text is directly inside flex child
- Broken: Text is in an
<h2>
inside flex child - Works: Text is in
<h2>
, butmin-width
set on flex child
overflow: hidden;
appears to also work, which I think makes more sense thanmin-width
(which is probably triggeringflex-shrink
).It’s good to see that the behavior is (a little more) consistent across browsers now. This was really frustrating at the time. Thanks for sharing!
This is actually much simpler than this. You don’t need the
min-width
hack for this to work. All you need to do is apply the following to the flex child and it’s direct child.You can view the Pen Flexbox and Truncated Text (no min-width hack) by Larry Gordon (@psyrendust) on CodePen.
I think applying one property on one element is pretty simple. I think your example above works because overflow hidden gets applied to the flex child, which works also (as zzzzBov noted above).
Chris could you throw a codepen of the initial problem you were trying to solve?
A cool little trick. I agree it’s a lot nicer to just set one rule than it is to start diving into the children and adding selectors in. Thanks, Chris!
And where is tooltip with hidden text?
+1 challenge to solve.
Thank you, but when would that be useful? Is there a way to truncate a word rather than text? Like the elipsis to appear after a word boundary? Thanks.
It’s working even without using flex, no need to use flex i suppose
min-width: 0
is not an hack, it’s by spec. Flex elements have as implicitmin-width
the content width, to prevent overflows (more at https://bugzilla.mozilla.org/show_bug.cgi?id=1108514#c5)Old versions of chrome wasn’t following the spec and was setting 0 as
min-width
The article links to and references the relevant parts of the spec. I didn’t say or mean to imply anything here is a hack. Interesting that it’s something that has changed over time in Chrome-land.
Sorry @Chris when I’ve talked about “hack” I was referring to the @LarryGordon sentence.
The real problem with text overflow and flexboxs is that a
display:flex
element doesn’t support ellipsis, you must wrap the text inside an additional divI think you might be wrong about this. #1 in the demo has ellipsis on the flex child itself.
@chris I was referring to this http://codepen.io/FezVrasta/pen/BKedgY
I come across this problem all the time!! But I am still struggling a bit.
What if there are 2 text nodes inside the flex child? I need to do this but only truncate the first text node. Take a look at this Pen to get an idea of what I’m trying to achieve: http://codepen.io/tgallimore/pen/aNqQzR
If anyone can help me do this with the second DOM structure in the Pen, I’ll love you forever!
The reason I need to use the second DOM structure is because we also need to make this work fro none flexbox browsers (with some acceptable differences). And it’s easy to do this with the second DOM structure by positioning elements absolutely and setting widths etc.
Seriously… Can no one help?
You can just put a
display: flex;
in.container2 .left-wrap
.It is what you are looking for if I correctly understand you.
That is exactly what I needed, thank you very much.
I’m sure I already tried something like this. Must have missed something though.
Thanks anyway.
Chris,
Here’s a flexbox niggle I’m struggling with:
Two child elements stretched and both used as flexbox wrappers themselves. The first child element is styled as thus…
Here’s the thing I can’t wrap my head around:
Since the container is stretched vertically and keeps the same height as its neighbor, how come when I set the last element in the child-element sub-flexbox to { align-self: flex-end; } it kicks that element out to the right (horizontally) not to the end of the stretched flexbox (vertically) when the elements are stacked in columns?
It defies logic.
Example: “Check us out at Retro booth B24-25” on http://epsilonlocal.com/retro/
Right now I’m using padding to push that phrase to the end of the flexbox, but I thought I should be able to set it there in the flexbox.
Cheers
@Ansel: Remove the align-self from the left column and then just use margin-top:auto on the element you want pushed down.
e.g.
The
margin-top:auto
pushes the element all the way down to the bottom.Here’s a similar example:
Thank you Mr. O’Brien!
That squared me away… but why does margin-top: auto; work in that way? I’m a bit confused how that’s the solution. In any event, thank you thank you thank you!
Cheers,
Ansel
@Ansel: Yes auto margins on flex items are a little bit of a secret and they will distribute any free space in that direction.
e.g. A fixed width and height flex item will be vertically and horizontally centred simply by using auto margins on all 4 sides.
https://www.w3.org/TR/css-flexbox-1/#auto-margins
Marcin Mendlik wrote in with a potential fix for IE 11.
I used just “0” in my own demo.