Grow your CSS skills. Land your dream job.

Line Clampin’ (Truncating Multiple Line Text)

Published by Chris Coyier

You want X lines of text. Anything after that, gracefully cut off. That's "line clamping" and it is a perfectly legit desire. When you can count on text being a certain number of lines, you can create stronger and more reliable grids from the elements that contain that text, as well as achieve some symmetric aesthetic harmony.

There are a couple of ways to get it done, none of them spectacular.

In case that explanation wasn't clean, imagine you have some HTML like this:

<div class="module">
  <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>

And you want to limit it to exactly three lines in a container. Like this:

In all these examples, let's assume we have a "module".

.module {
  width: 250px;
  overflow: hidden;
}

Weird WebKit Flexbox Way

David DeSandro showed us this little ditty a few years ago.

.line-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;  
}

One one hand, this is awesome and exactly what we need. CSS the perfect place for this. It's a real need and it should be this simple.

On the other hand... it's weird. why does it need to be a flexbox thing (the old version at that)? It doesn't work without that. And it's extremely fragile. Let's say you want the module (or the paragraph) to have some padding. You can't, because the padding will expose extra lines. That's what we get with half-baked non-standardized properties.

The Fade Out Way

The root of this technique is just setting the height of the module in a predictable way. Let's say you set the line-height to 1.2em. If we want to expose three lines of text, we can just make the height of the container 3.6em (1.2em × 3). The hidden overflow will hide the rest.

But it can be a bit awkward to just the text off like that. Ideally we would add ellipsis, but we can't reliably position them. So instead we'll fade out the text achieving the same kind of communication ("there is more...").

To fade out the last line, we make a box (a pseudo element will work great) and overlay a transparent-to-background-color gradient over the top. Making it nearly as wide as the container is best in case the last line is short. Because we know the line-height, we can make the pseudo element box exactly one line tall.

.fade {
  position: relative;
  height: 3.6em; /* exactly three lines */
}
.fade:after {
  content: "";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  width: 70%;
  height: 1.2em;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1) 50%);
}

The Opera Overflow Way

Like WebKit, Opera has their own way to handle this. They apply ellipsis on the line you wish to. Of course the clock is ticking for Presto (Opera's rendering engine pre-Blink) so this isn't particularly useful. Perhaps it can still inform a future implementation though.

.last-line {
  height: 3.6em; /* exactly three lines */
  text-overflow: -o-ellipsis-lastline;
}

The Clamp.js Way

Where there is a will there is a way (with JavaScript). I think that's a saying. Joseph J. Schmitt has an excellent library-free JavaScript thingy called Clamp.js for making this happen in a cross-browser way.

var module = document.getElementById("clamp-this-module");

$clamp(module, {clamp: 3});

Make sure you target the element with the text directly inside of it. Originally I tried putting the ID on the module, which worked in Chrome/Safari, but failed in Firefox. Putting it on the <p> made it work in both (Thx Merri).

The Demos

Check out this Pen!

Update: More Good Ways!

  • There is an exceptionally clever all-CSS way to do this posted on the Mobify blog.
  • Vesa Piittinen created an alternative method to Clamp.js.

    Unlike Clamp.js it retains all the text within the clamped element and uses text-overflow to do the magic.

  • FT Labs also has created a JavaScript plugin to do the job. It's nice in that you don't have to specify the number of lines, it just happens when the text overflows the container, so the design decision stay in the CSS.
  • Succinct:

    A tiny jQuery plugin for truncating multiple lines of text.

Both of these examples have been added to the main Pen.

Comments

  1. Matt

    The Clamp.js method actually did not work for me (FF 20). I still think the method I prefer is the gradient overlay. Another element could then be placed over the pseudo-element to further indicate more content (a “Read more” link). That said, without some major hacking for IE, this leaves us still looking for a good cross-browser method.

  2. Jason

    Attempting to achieve the elegant truncation has been a bane on my existence since beginning work in web development. Thanks for pointing this feature out; I will definitely be using it.

  3. I’ve implemented a simple jQuery plugin that allows you to achieve something like this and then some.

  4. Rick Meijer

    No love for text-overflow: ellipsis?
    It only works when there’s white-space: nowrap active as well.

    • BigBossSNK

      text-overflow: ellipsis only works on the first and only line of text, though.
      The article’s point is, what can we use to indicate overflow when text wraps on multiple lines.

    • You can actually use white-space: pre and it works for each line.

      What this means you can write some JavaScript to add two line changes or so and then the last line gets ellipsis.

      The difficult part is measuring text in an efficient manner.

    • BigBossSNK

      I wasn’t aware of pre’s cross-over with overflow, Merri, thanks for the info.
      Still, that solution requires JavaScript, and it changes the content itself.
      Text you copy-paste will have new-lines in it.
      That’s not acceptable for my usual use-case, but other people wouldn’t mind.

  5. 1UnitedPower

    The w3c targets this problem in its “CSS Overflow Module Level 3″-working-draft.

    Based on this very early spec, we theoretically can do the 3-line clamp like so:
    .line-clamp {
    overflow: fragments;
    }
    .line-clamp::nth-fragment(1){
    max-lines: 3;
    }
    .line-clamp::nth-fragment(2){
    display:none;
    }

    • MaxArt
      Permalink to comment#

      Granted that it’s an early spec, but that doesn’t actually help in any way. We’re already capable of truncating text after n lines, our problem is putting the ellipsis at the end of the desired lines.

      So we have our fragments, and we’re hiding all of them except the first one. But what do we do with the first fragment?

      It looks to me that spec is more about addressing the same problem of CSS Regions. But what we actually need is some :overflowing pseudo-class. Designers are asking for it since, like, 1998…

  6. DolphinDream

    The fade-out-way has a lil gotcha… what if the text fits exactly in 3 lines? In this case you would NOT want to fade out the end of the third line, since there is no more content following. Surely if you know the text fits, you wouldn’t try to clamp it, but if you don’t know…

  7. I like the gradient way too (after a decent standardized clamping method of course). I really do think you’d need a pointer-events: none; on the pseudo-element though.

  8. As it seems Clamp.js just doesn’t work. So after some trial and error this instead seems to work reliably cross-browser:

    It needs some further optimizations, it really doesn’t need to edit the data string like it does and it could just go ahead and create the elements in the first replace callback loop.

  9. Glen

    The fade out technique is similar to what polygon Polygon uses.

  10. Thanks for the useful post, Chris.

    The guys at FT Labs also developed ftellipsis that does the same thing, and falls back to clamping text and positioning an element over the end of the overflowing line in non-Webkit browsers.

  11. … and used wrong name… Anyway. Clamp.js works after all, Chris just targets the wrong element in his sample (id should be in paragraph not in the div).

    What I don’t like about Clamp.js is how it removes original text from the element.

  12. Sad Guy

    As a new comer to Web Design, I find all this little things insane. Even programming games is less of a headache than web design, I was surprised.

    I had to do exactly this a few days ago for my site, and the solution I found was to do a word wrap AND count the lines via PHP. Not to mention get a script that would make sure to not count HTML tags as words.

    So when is one of you guys going to code a whole new way to make websites, one that is logical, consistent across browsers and does without pain basic things? I’ll send $100 to your paypal when you do it, maybe even more.

  13. WOW! I like Clamp.js it only seems to work in a -webkit- browser.

  14. Some interesting examples of how to achieve this, when we’ve done it in the past we’ve used PHP to accomplish this, with any luck we can do away with that soon!

  15. Guy

    I don’t get how “The Fade Out Way” can work at all since you can’t guarantee the same font size across browsers.

    Even if you set line-height and font-size, the text will still overflow at different areas. Depending on the browser it may stop just before the container ends, but on other browsers the last line can be cut in half by the container.

  16. Dave Schoutens

    I recently did some poking around online for a solution to this problem, and I landed on a jQuery plugin called dotdotdot. Clearly, it’s not a pure CSS solution, but CSS effectively controls it’s application, since the library measures the text container, and only applies to overflowing content.

    One of the coolest features of ‘dotdotdot’ (and the main reason I chose it over other solutions) is the ability to ensure specific content remains visible, or add custom content when the ellipsis is needed. In my particular case, I was clipping product descriptions on an ecommerce site, and needed to ensure the product ID remained visible at the end of the description, even when an ellipsis is present.

    The library has served me very well so far, and I recommend it highly. I haven’t yet needed a ‘dependency-free’ version (no jQuery) yet, but when I do, I’ll likely contact the developer asking for a vanilla-JS port, or do it myself.

  17. Paolo Priotto

    Check out https://gist.github.com/depoulo/5832073
    CSS only, accounts for the case where you have text as long as the number of lines you want to show (you don’t want dots then), and you can implement a -webkit-line-clamp switch into it easily.

  18. Oshios
    Permalink to comment#

    Opera Overflow Way is not work. I guess because the Opera is changing the engine of their own.

  19. I like Clamp.js it only seems to work in a -webkit- browser.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".