CSS3 text truncation and ellipses: even in Firefox, and without the styling constraints

[Update: This trick became obsolete when Firefox 4 was released in the first half of 2011, when Mozilla removed the features that made this workaround possible. So, for a time, there was no easy way in Firefox to get the text truncation with ellipsis at all. However, beginning with Firefox 7, text-overflow: ellipsis is finally supported. Yay!]

CSS3 provides a great convenience when it comes to truncating too-long text: the text-overflow property, which automatically selects the best truncation point and adds ellipses. Unfortunately, it doesn’t work in Firefox. There’s a hack to make Firefox do this, too, but it comes with tight constraints on the structure of your HTML, preventing any but the absolute simplest text styling. Here’s a way to get around those constraints and style your text however you want.

For my first “serious” post in this blog, I’m definitely diving into the deep end of the pool, because I am by no means a CSS expert; I’m not even all that good at it. But I seem to have hit upon the answer (or at least the last 10% of the answer) to a problem that other people are struggling with, too, so I thought I should share it – and get off my duff and finally launch this blog before I forget what I did!

The problem: automatic text truncation

In my work at Kachingle, I’m responsible for the widget we call the “Kachingle Medallion”. This medallion sits on participating websites, and we serve it up dynamically, customizing it with a color-coded coin and the number of “Kachinglers” for each site. But now I needed to further customize it by adding the name of the hosting website:

image of medallion with a short site name that fits; text on three lines reads: 2 Kachinglers for Sharon's test site. How about you?

Since the site names are provided by our users, of course they can be any length. And that means we need a way of truncating the name when it’s too long, and adding an ellipsis.

One could always impose a simple character length limit to decide where to truncate, but that would be less than ideal here. The size of the space available is constrained, and we’d like the ellipses always to appear at the right edge, allowing as many characters as will fit, but no more. That number will be different depending on whether the site name contains lots of i’s or lots of W’s; and it will change if I happen to change the dimensions of the containing element or the style of the text. What’s needed is a way to truncate at the time the text is rendered, based on its rendered dimensions.

CSS3 text-overflow (except in Firefox)

Justin Maxwell’s fabulous article, CSS String Truncation with Ellipsis, starts by explaining the basic CSS3 solution for this. Most modern browsers already support the CSS3 text-overflow property, which will automatically calculate the right place to truncate text, and add the ellipsis. In my case, like this:

<p class="ellipsis">
    2 Kachinglers
    <br />for <span class="emphasize">Sharon's test site</span>
    <br />How about you?
</p>

where the “ellipsis” rule gives me the required properties for the truncation:

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

and the “emphasize” rule gives me my highlighting. So now, when I replace “Sharon’s test site” with “Site With a Really Long Name”, I get this:

image of medallion with correct truncation and correct styling

Alas, I said “most” modern browsers. We can include Opera by using their proprietary name for the same property, -o-text-overflow. (And Justin suggests IE8 requires -ms-text-overflow, although it seemed to work without it for me.) But unfortunately, Firefox doesn’t support this at all yet, by any name whatsoever; so the exact same code renders in Firefox like this:

image of same code rendered in Firefox with non-truncated text overflowing the margins

The very clever work-around for Firefox

Justin goes on to explain a work-around, originally worked out by Rikkert Koppes, which simulates this feature in Firefox. I won’t repeat all the details here but I urge you to check out both articles. The technique requires adding the “-moz-binding” property to my .ellipsis class, and linking that to a special XML file, like this:

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;	/* required for Opera */
    -ms-text-overflow: ellipsis;	/* required for IE8, allegedly */
    -moz-binding: url('ellipsis.xml#ellipsis');    /* for Firefox; details here */
}

That last line will have no effect on the other browsers, so I should be all set.

Unfortunately, implementing this solution has some requirements that force me to change around my HTML a bit. If I simply enhance my .ellipsis class as described above, the <span> containing my highlighted text disappears entirely in Firefox! As do the <br /> elements between the lines. That’s because, as Justin explains, this technique constrains the truncated text to contain only minimal markup structure. It can’t contain “mixed” content, e.g., text next to other nested elements, as I have above. This makes it hard to apply any but the simplest styling to the text.

No problem, I thought — I’ll just put the .ellipsis class on the <span> itself, instead of on the paragraph:

<p>
    5 Kachinglers
    <br />for <span class="ellipsis emphasize">Site With a Really Long Name</span>
    <br />How about you?
</p>

But this caused a cascade of other problems. Because now the truncation point (in all browsers, not just Firefox) is calculated relative to the right edge of the span instead of the right edge of the (fixed width) paragraph, and the span overflows well past the edge of the paragraph, making any truncation or ellipsis invisible. In order to rein it in, I need to apply style display:block to it. But that in turn prevents it from appearing on the same line with the preceding text (“for”)! (Admittedly, this was where my inexperience with CSS was apparent, and maybe I missed something there.) My stopgap solution was to put the entire line, including the “for”, inside the span (and I have to remove the <br /> after the span as well), leaving me with this:

<p>
    5 Kachinglers
    <br /><span class="ellipsis emphasize">for Site With a Really Long Name</span>
    How about you?
</p>

and:

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    -ms-text-overflow: ellipsis;
    -moz-binding: url('ellipsis.xml#ellipsis');
    display: block;
}

This works. I now have proper truncation with ellipses in Firefox (and everywhere else):

image of medallion with entire line highlighted, not just the site name

But this was pretty disappointing. I did not want to be forced to have uniform styling for the whole line. (And this will be the appearance in all browsers, unless I add additional, more complex code to distinguish between them.) What’s at the root of the problem is the limitation that this solution imposes on markup structure. There was no way to divide the line into separately styled subsections and still get them both to coexist on the same line. Justin’s and Rikkert’s posts, along with the numerous comments on each of them, point out this problem but don’t suggest any way around it.

Making it do my bidding

I tried many different ways to structure the markup and the CSS that would give me the styling I wanted, along with the ellipsis. But nothing seemed to work. My choices seemed to be either to accept the uniform styling, or to put the “for” someplace else (which is not really a solution). I reluctantly accepted it, and gave up for the day. But a good night’s sleep helped me think outside the box model (so to speak).

The solution is to use absolute positioning for the <span>. This takes it out of the rendering flow, so I can now put it wherever I want it.

Perhaps this takes a hack and turns it into even more of a hack – but it works! The <span> now has to be carefully positioned, and this was somewhat of a trial-and-error proposition for me. And that positioning didn’t work too well until I put the “for” in its own absolutely positioned <span> as well, otherwise getting the two to line up was difficult and browser-dependent. And both spans need to have class .ellipsis applied, even though the first one will never actually need truncation. The second span must now be given an explicit width in order for its margin to line up properly, since its default width seems no longer tied to the width of the <p>. Finally, two adjacent <br /> elements put the third line in the right place, to leave a gap for the absolutely positioned line.

The final result looks like this:

<p>
    5 Kachinglers
    <span class="ellipsis position1">for </span>
    <span class="ellipsis position2 emphasize">Site With a Really Long Name</span>
    <br /><br />How about you?
</p>

and:

.ellipsis {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    -ms-text-overflow: ellipsis;
    -moz-binding: url('ellipsis.xml#ellipsis');
    display: block;
    position: absolute;
}

/* The following are particular to my case and are only for illustration */
.position1, .position2 {
    top: 42px;	/* both spans lined up the same */
}

.position1 {
    left: 8px;	/* Same as the padding in the <p>, so that the margin lines up */
}

.position2 {
    left: 24px;	/* come right after the preceding text */
    width: 81%;	/* truncate in the right place */
}

image of medallion in Firefox with correct truncation and correct styling

And there we are. Proper truncation in Firefox, without being constrained by the markup rules of the -moz-binding solution! This approach should work for any kind of styling or formatting that would normally require nested elements, including making a link out of a subset of the truncated line, and maybe other uses I haven’t thought of. So, what do you think? I’d love to hear if this is of use to anybody, and what you do with it.

This entry was posted in CSS3 and tagged , , , , , , . Bookmark the permalink.

10 Responses to CSS3 text truncation and ellipses: even in Firefox, and without the styling constraints

  1. To see Sharon’s brilliant solution in action, please visit my blog posts on the Kachingle blog!
    Cynthia on the Kachingle Blog

    • Disclaimer: Cynthia is the founder and president of Kachingle and has a vested interest in everybody thinking my solution is “brilliant”. I actually think it’s kind of obvious – once you know the answer! I just hadn’t seen anybody else publish the answer. :-)

      • C says:

        Now now, Sharon — accept some praise now and then! What’s obvious to you is probably not to most of the population, after all :)

        • Now and then, I do. :-) Hey, it wasn’t obvious to me, either – except in 20/20 hindsight. I will accept that it was a “clever” solution, or a “creative” solution. The highest praise will be to see if others find it useful.

    • And the Medallion is now “in action” in this blog’s sidebar, too. (Try mousing over it.)

  2. Pingback: Kachingle Blog : Kachingle engineer Sharon adds to the CSS3 knowledge base regarding tricky text truncation

  3. Pingback: The Impact of Graphic Design on Software Engineering | In Silico

  4. tim says:

    so now people who have 3 minutes of wisdom to share also want to nickle and dime me for reading their post?

    talk about dark ages… a penny for your thoughts, no thanks. id rather pay real money for something substantive lik nyt than kachingle a blog of mediocre quality…

    • Thanks for the feedback, Tim. Well, I’m sorry my coding example wasn’t helpful to you. Your mileage may vary, right? This post was about CSS3, not about Kachingle. But to answer you directly: you’re free of course to pay for good journalism, but we at Kachingle expect that more and more “substantive” sites will also be using Kachingle, or something like it, soon, because the reality is, most people won’t pay for subscriptions, and that model won’t work. And remember, with Kachingle you never have to pay for anything unless you want to. You never have to pay for mediocre content like mine. Thanks for reading, anyway!

  5. Pingback: lonnie