The trick in this article is still pretty neat and clever, but there is a now-standardized way to do this which is probably your best bet.
Truncating a single line of text if is fairly straightforward. Truncating multiple lines is a bit harder. Using just CSS (no JavaScript or server-side dancing) is nice for the simplicity. It’s gotten a little easier lately since Firefox (since version 68) has started supporting the ultra-bizarre -webkit-line-clamp
soup method, which makes browser support for that pretty OK.
There is another way though, which is very clever and something I’d call a bonafide CSS trick. We somehow failed to cover it properly in our canonical post on line clamping, so I’ll cover it here then add it to that post. I first saw this trick on the now-dead Mobify blog, and more recently covered by Natalia Onischuk on HackingUI.
The trick uses line height for measuring
Here’s a big part of the trick. Imagine an element has a line-height
of 1.4rem
and you want to make sure it only shows a maximum of three lines of text. If you set the max-height
to 1.4rem * 3
, you’ve done it!
I’m not the worlds biggest fan of united line-height
, but alas, it’s necessary here to do the math. I’m also not the biggest fan of setting it over and over on elements, so let’s set a variable we can use later, and then use it to set a global line-height
.
html {
--lh: 1.4rem;
line-height: var(--lh);
}
Set that max height
The truncation happens just like this:
.truncate-overflow {
--max-lines: 3;
max-height: calc(var(--lh) * var(--max-lines));
overflow: hidden;
}
You actually could leave it like this. That might be good enough if you don’t care about the ellipsis.
The rest of the trick comes in when you want to display that ellipsis stuff
An ellipsis (“…”) signifies that text has been truncated and continues longer than what it displayed. Using it is probably a pretty good practice when truncating text so the content doesn’t come to an abrupt, awkward end. (Well, the content itself might be awkward anyway, but hey, you tried.)
If you set position: relative
on the element, you can absolutely position the ellipsis in the bottom-right corner.
.truncate-overflow::before {
content: "...";
position: absolute;
bottom: 0;
right: 0;
}
I was very tempted to, instead of setting the bottom, to set the top and use top: calc(var(--lh) * (var(--max-lines) - 1))
. My thinking there was that you might as well place the ellipsis at the exact point you need it. If the text is too short, the hidden overflow will cut it off. The problem with that is that it doesn’t deal with the “exactly max lines lines” problem. The ellipsis will show when the text matches the max lines — not only when it exceeds that space.
We’ll have to get trickier!
Note that this “setting stuff in the bottom-right” thing is pretty specific to left-to-right languages. I’m going to make the demo with CSS logical properties like inset-inline-end
instead of right
in hopes to make it more friendly to different languages and flow scenarios.
Another limitation is that the ellipsis doesn’t attach itself to the final word since it’s absolutely placed. We’re not going to fix that as well.
Let’s cover up the ellipsis when the text is too short
This is the second part of the trick. If we position the absolute at the bottom/end of the text all the time, that’s fine. But if the text is exactly equal to the --max-lines
value or less, we want to hide it.
The trick there is to make a little box that is the same background as what is behind it and set it on top of the ellipsis to cover it. We can do that with the other pseudo-element:
.truncate-overflow::after {
content: "";
position: absolute;
right: 0; /* note: not using bottom */
width: 1rem;
height: 1rem;
background: white;
}
Another trick we’re using here is not setting a bottom (inset-block-end
) property. This places the box at the bottom of the content rather than the bottom of the relative parent, which is very useful.
Let me make the boxes red so you can see them in these three different examples:

--max-lines
.Demo
I used wanted to use CSS logical properties here, as the browser support has gotten pretty good. If you’re supporting any version of IE, you’ll have to use the bottom
and right
.
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
89 | 66 | No | 89 | 15 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
117 | 117 | 117 | 15.0-15.1 |
Accessibility Concern
Joseph Scherben wrote in to mention:
If the elements contain interactive elements and the overflow is hidden (not scroll) those elements would be focusable but not visible in the site. Which could cause keyboard/assistive device users to lose their place in the hidden cropped content
It’s probably due to my hi-res monitor, but in the demo the ellipses are only half obscured by the white box. Regardless of that, you still only have the ability to position the ellipsis in the corner of the box, as opposed to immediately following the truncated text. This is one of those solutions that I consider to be very clever CSS, and useful in a pinch, but ultimately something that there really ought to be a better spec for by now.
Just to make sure that people don’t get the wrong impression, the “ultra-bizarre
-webkit-line-clamp
soup method” may look weird, but it has recently become widely supported in all modern browsers, and it works without any major issues (at least, none that I’m aware of).Unfortunately, some
-webkit-
properties have become the standard now, but that should be no reason to avoid them if they get the job done.I called it that in a sentence literally talking about the recent good browser support for it.
Neat trick! Things like this dumbfound me though as to why its so complicated. And all the solutions I’ve seen are based off of the number of lines.
text-overflow: ellipsis;
just works no matter how wide the container that is being overflowed is. Why isn’t there a multi line solution that works the same way? What if I want my container to be a dynamic height and also have the text have ellipsis at the end if it overflows?Seems to me like this problem is being severely over engineered (Not your solution, just the feature/issue in general). Want 4 lines of text? Set the height of the parent equal to 4 x of the line-height. And just let the text clamping/ellipsis be dynamic based off the available height and width.
Describing something as getting ” a little easier” and “bizarre” does in no way suggest it’s de facto working in all major browsers, is I think, the point.
I am having the same issue as Alex. I am seeing part of the dots on the last 2 paragraphs. Firefox 68 on Win10.
The ellipsis in the right corner isn’t so bad if you also use
text-align: justify
to align the right edge.This would have been a nice trick many years ago, but as Šime Vidas said, the
-webkit-line-clamp
property is a better choice and is widely supported: https://caniuse.com/#search=line-clamp.You could leave the line height unitless and just multiply the answer by 1rem I think.
At least I do something similar with the WebKit line clamp method
I listened to the State of CSS Shop Talk Show podcast shortly after reading this article. It got me thinking about CSS Exclusions and if they could be used to improve this effect a bit. I kinda like where it ended up in IE11 + browsers that support line clamp: https://s.codepen.io/soluml/debug/KOKGmB/wQAPoNnKJxnr
I am trying this cool trick but how would you handle if you need to have min-height set (1.4rem *3 ) and you just have 1 line of content
what about -webkit-box-orient ?
I can use it or it’s not supported?
I hate always being a stickler, but I am what I am. An ellipsis is its own character, …, that can be typed as ⌥. (Option+Period) on a Mac. It looks like three periods, but most fonts adjust the spacing when compared to three periods. The article text and CSS code above technically just use three periods. Using the actual ellipsis character would be a subtle but classy touch, more likely to look like a native control.