Ellipse my text…

You may be starting to notice a trend from my recent articles here on HTML5Hub. I’m a JS snob by trade, but by association I have to deal with my fair share of CSS issues. So, as an “outsider” looking in, I’m taking this opportunity to highlight some of the big “pain points” that CSS causes for various basic tasks in web dev. It’s not really intended as a criticism of the technology per se, but more a rallying cry to ask for standard solutions which remove our hacks.

More Text, Less Text

If you’re a prolific (and overly verbose) writer like I am, you’re probably very familiar with writing too much to fit in the space you’re given to present it. Sometimes you want to manually truncate your own text, but more often, you’d probably just like the presentation platform to automatically take care of this for you.

Many people call this “ellision” (verb: “elide”), when you shorten your text, and put those little dots after it. Turns out that’s not quite correct. Elide actually means to omit part of a word (syllable, etc) in verbal pronunciation, such as “o’er” instead of “over”.

The “…” is called an ellipsis and the verb form (according to wiktionary) is ellipse (no, not just the geometric shape!).

With the explosion of responsive-layout obsession around the web these days, the amount of space your text lives in has never been more dynamic (subject to change). More than ever before, we need good ways of signaling to a reader that there’s more (text) than meets the eye.

I’m not going to cover why or why not you choose to ellipse your text. That to me is an orthagonal question. I’m just assuming here you have good UI/UX reason to do so, and so let’s address how you do it.

Let’s quickly take a look at how we currently can accomplish this task, and possibly how we should be able to do it.

Dot-dot-dot

First, there’s the manual way. I’m typing along, and I realize that I want to convey that something continues or is paused, so I just … dot3x myself.

This is obviously the least flexible way, because you manually calculate where you want to put those dots (aka, periods), and that can’t be adjusted if you have more or less space available.

JS to the rescue?

A variation of this technique is when you use JavaScript to ellipse your text. For instance:

Again, you’re basically making assumptions about the length of the text relating to its visible dimensions. The assumptions sometimes work out, but more often than not, it’s not quite gonna cut it.

Note: For brevity I won’t cover it in detail, but you can devise a JS algorithm that attempts to layout text in an element, and tries to manually truncate the text one character at a time until you no longer have any overflow (have to examine the dimensions of the text element as compared to its container), then you’ve decided how many characters can appear, then call something like the  shorten(..) I show above. While these elaborate techniques are a bit more complicated to implement, they do at least reduce some of the assumptions, but they are still brittle to changes in container dimension (have to re-calculate each time!)

…

Instead of putting in 3 separate “.” characters, you can (and probably should!) insert the ellipsis character itself, as an HTML entity:  … … The advantage is that this single character is a bit more predictable in terms of size, and as an HTML entity, its display is more consistent across fonts and font-sizes (which should make your calculations a little easier).

But this is still largely manual ellipsing, so the above caveats apply.

text-overflow:ellipsis

Quite awhile back, CSS added a feature to the  text-overflow functionality that has CSS basically do what I suggested, which is automatically figure out how much text can be shown, and truncate with an ellipsis.

This sounds like the ideal solution, until we consider some of the caveats.

For one, you also have to specifically control the  overflow of the parent container. It stands to reason that if the default  overflow:visible (or  overflow:scroll) is applied, there’s no point in truncating/ellipsing the text. So, you have to pick  hidden or  clip so that there’s a reason to ellipse. But it is a little annoying that you have to specify both  overflow and  text-overflow.

Also, the parent element has to have a specific width, or at least a max-width. It can’t be shrink-wrapped around your text content and growing without bounds, or again, it would be non-sensical to also ellipse text.

Lastly, and worst of all,  text-overflow:ellipsis only works on single line of text. That is, you can’t simultaneously have the text wrap to subsequent lines and have it ellipse at the end of the last line.

Bummer, because that’s exactly what you’d probably want, like for instance displaying news items or tweets in a compact space, you’d want to show the first 2 lines and then ellipse the rest, possibly to reveal on hover or on click.

Experiments

Opera has had (queue sad-face)  -o-ellipsis-lastline, which would have been awesome. For some reason, that never became standard, and I guess now it’s been abandoned. Oh well, it was nice while it lasted.

Then there’s the webkit-only tricks which use something they call  (-webkit-)line-clamp.

Finally, a rather clever but elaborate workaround where you truncate text but then use a  ::after pseduo-class to insert your   at the end, and only if the text would have overflowed, has been demonstrated as possible.

But there’s simply no question that these things are unfortunate (proprietary) and/or hacky.

…?

Can we please come up with something better? What about standardizing Opera’s idea?

Or, what about:

As always, what do you think? Am I crazy, or couldn’t this be a simple task that we standardize into some feature instead of hacking around?

Tell us what you think!?

  • Tom

    I was very excited when I discovered text-overflow: ellipsis; a few years back but, as you said, there aren’t many situations where you’d need this with a single line :(

  • bebraw

    I’ve written a small plugin that deals with some common scenarios in JS. I am sure there are plenty of those available, though.

    It would definitely be nice if there was some standard way to achieve this.

  • Barney Carroll

    I recently wrote a small pure-CSS * system for this: http://jsfiddle.net/barney/bmNvs/. Our scenario was that we had to support IE6, the content was in proportional table cells whose container changed size continuously, and we basically just had to indicate that there was extra content to read (a click would take the user through to a view where the content was fully expanded)

    * You’ll need a wrapping block element around an inline element containing the text, and one element of extra markup for browsers that don’t support pseudo-classes.

    • Ganesh

      This solution is awesome. Thanks.

    • nick turitto

      This works great! Do you have a solution that doesn’t need the white backgrounds? For instance, I am wrapping in a datatable with striped rows, so there are 2 possible background colors. If I omit the background properties, then the ellipsis is shown no matter what. Very good solution.

      • Barney Carroll

        Absolutely. My revised solution uses `background: inherit`. You can use any background, and it will pull through — I thought you might need to specify `background-position: fixed` on the parent when using images, but from my experiments so far (with CSS3 backgrounds), that’s not the case.

        Check out this example:
        http://jsfiddle.net/barney/7PjY8/

        • nick turitto

          Thanks for your help, Barney. Much appreciated

          • Barney Carroll

            Hey Nick, that example I gave you was broken. Check out this fixed and much neater code (no presentational elements, yay!): http://codepen.io/barneycarroll/pen/acJpA

          • Nonox

            Hi, thanks for sharing, works great on Chrome, however I couldn’t manage to make it work on IE8 : the ellipsis is always shown even with short texts. Any idea ?

          • Barney Carroll

            I don’t know what could be causing that. I would suggest replacing the :before and :after pseudo elements with real elements (empty spans, for example) and use developer tools (F12) to try and work out why the fill element (:after) isn’t covering the ellipsis (:before).

          • Barney Carroll

            You can get this to work as far back as IE6 if you’re willing to use a couple of elements instead of :before and :after. IE8 pseudo-elements support is a bit sketchy if memory serves, so you might want to try this.

          • Nonox

            Indeed, I managed to make it work on IE8 using real elements before and after the text, works OK :-)

        • http://barre.me/ Sebastien B

          Great solution. Am I correct to assume that all the background: *-linear-gradient CSS properties have to be overriden for the correct gradient to show up on a background that is not white?

          • Barney Carroll

            Yes — essentially you have to make sure the container has whatever background property you want explicitly set, otherwise the ellipsis elements will inherit the default background property ( transparent ) and the ellipsis will appear on top of the text…

          • Barney Carroll

            No — you apply the background to the container (and actually, you *do* have to apply `background-attachment: fixed` for it to work), and then the `background: inherit` properties on the ellipses elements sorts out the rest.

            My previous example was broken: I created a new one that uses pseudo-elements to create the ellipsis effect, and demonstrates how to use background imagery and strict vertical rhythm to create a zebra-stripe effect.

            http://codepen.io/barneycarroll/pen/acJpA

        • Muber

          Does it work if text is centered? Seems ellipsis is always positioned right.

          • Barney Carroll

            No, that won’t work I’m afraid — the ellipsis needs to hug the edge of the containing element. Sorry!

  • Marcelo Manzan

    A while ago I had made a jQuery Plugin to solve this issue. Unfortunately there have been changes in the way jQuery-Plugins are shared, and it was lost. I did a POC that illustrates the operation of the plugin, but I’ll elaborate on later and publish the plugin more adequately. Enjoy it: http://jsfiddle.net/3gcjj/ (you can resize some elements and see the changes on-the-fly)

    • Neil Monroe

      Good job with the fiddle!

  • Nathan Mynarcik

    Ellipsis has been a headache for so long. I have used all the approaches mentioned for production level projects and none seem to be ‘best’ across all browsers. This is a common utility that is used daily and shouldn’t require plugins or even JS for that matter to accomplish. We can only keep trying to push this to be implemented for all browsers in a more reasonable approach (most likely CSS).

  • Will Shown

    Keep publishing articles like this! Opera’s implementation definitely makes the most sense (IMHO) and should be standardized, and if we keep shouting about it maybe a browser vendor will finally hear us.

  • http://sebastian-werner.net/ Sebastian Werner

    Definitely should be implemented. I would suggest keeping the text-overflow property as is and adding a new property called text-lines: 3 which defines the number of lines to render. Generically. Could also be useful in other situations…

    • http://getify.me/ getify

      But what if you don’t know how many lines should show? If you’re using em’s for font size for instance, sometimes 2 lines, sometimes 4 lines… need something more relative I think.

  • pbojinov

    The approach that I have been using to shorten text is to not add … in the middle of a word, which is hard to read. e.g “hello my na….”

    I limit the text to the minimum number of words whose total length minus 3 is less than the max length specified, then append three dots to it.

    Then the text won’t get chopped and instead will look like this, “hello my…” or “hello my name…”, which is much more legible

    see JavaScript code example here – https://gist.github.com/pbojinov/6531779

    • http://getify.me/ getify

      How does that handle a URL for instance, which may very well not have any word breaks you could normally shorten at?

      • pbojinov

        That’s a really good use case that I haven’t come across because I’ve only been using this to shorten plain text content without URLs in the mix. At the moment I believe it will just cut out the whole URL if it is over the character limit.

  • Christopher Sanders

    I totally am in agreement that they should absolutely be adding this to the standard. Webkit should add this. Let the people decide how to gracefully cut off text when it overflows….rather than waste content writer and developer time trying to tack around this limitation.

  • Enno Ostendorf

    Such a CSS-Attribute would indeed be nice, but it should include a technique to display the unabbreviated text while hovering maybe in a tooltip so it behaves somehow like the title Attribute.

    But then we have the same discussions as with the title attributes – they are not stylable, and the designers don’t like that.

    So as long as we have designers, we have to use JS to measure the length of the text-container, cut it, insert the ellipsis and add an event handler to display the whole text on hover.

  • John Doe

    In the first sentence of your “Experiments” section, I think you wanted to use “cue” rather than “queue”.

    • ninjaf

      I thought the same thing. Why would he want the sad face to stand in line? ;-)

      • mamapitufo

        maybe he’s optimising… something might wipe out the sadface before the next frame?

  • Angel

    I’m guessing you could use the single line ellipsis adding a span to the last line of your text with php, couldn’t you?

  • mikedice

    Agree with the author. Too bad this isn’t supported explicitly in CSS. I wanted little article divs that contain article content and I wanted the text to be truncated with … if the text length would cause the container’s vertical height to grow too large. My solution, draw the article container off screen and trim words from the end until the vertical height fit my specification. Once it fits, move it back on screen. This has the benefit of letting the layout engine do the work of measuring the height using all my styles and whatnot while I trim words. Once trimmed so the text fits in the height I wanted I just append ‘…’ . Also, I didn’t want to append ‘…’ if the content fit without me doing any word trimming.
    My solution: http://jsfiddle.net/mikedice/fEbM4/2/

  • Naftoli Gugenheim

    s/queue/cue :)

    • badmonkey0001

      s/s/queue/cue/s/queue/cue//

  • Nathan Swartz

    Seems this doesn’t work in Firefox. I’ve been experimenting for a bit now and can’t get it to stick, Dave Walsh seems to think the same thing: http://davidwalsh.name/css-ellipsis

  • http://www.joshpalmeri.com/ Josh Palmeri

    No, you’re not crazy. Yes, this should be a standardized property.