Truncating long strings with CSS: feasible yet?

Viewed 142608

Is there any good way of truncating text with plain HTML and CSS, so that dynamic content can fit in a fixed-width-and-height layout?

I've been truncating server-side by logical width (i.e. a blindly-guessed number of characters), but since a 'w' is wider than an 'i' this tends to be suboptimal, and also requires me to re-guess (and keep tweaking) the number of characters for every fixed width. Ideally the truncation would happen in the browser, which knows the physical width of the rendered text.

I've found that IE has a text-overflow: ellipsis property that does exactly what I want, but I need this to be cross-browser. This property seems to be (somewhat?) standard but isn't supported by Firefox. I've found various workarounds based on overflow: hidden, but they either don't display an ellipsis (I want the user to know the content was truncated), or display it all the time (even if the content wasn't truncated).

Does anyone have a good way of fitting dynamic text in a fixed layout, or is server-side truncation by logical width as good as I'm going to get for now?

6 Answers

Update: text-overflow: ellipsis is now supported as of Firefox 7 (released September 27th 2011). Yay! My original answer follows as a historical record.

Justin Maxwell has cross browser CSS solution. It does come with the downside however of not allowing the text to be selected in Firefox. Check out his guest post on Matt Snider's blog for the full details on how this works.

Note this technique also prevents updating the content of the node in JavaScript using the innerHTML property in Firefox. See the end of this post for a workaround.

CSS

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

ellipsis.xml file contents

<?xml version="1.0"?>
<bindings
  xmlns="http://www.mozilla.org/xbl"
  xmlns:xbl="http://www.mozilla.org/xbl"
  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
>
    <binding id="ellipsis">
        <content>
            <xul:window>
                <xul:description crop="end" xbl:inherits="value=xbl:text"><children/></xul:description>
            </xul:window>
        </content>
    </binding>
</bindings>

Updating node content

To update the content of a node in a way that works in Firefox use the following:

var replaceEllipsis(node, content) {
    node.innerHTML = content;
    // use your favorite framework to detect the gecko browser
    if (YAHOO.env.ua.gecko) {
        var pnode = node.parentNode,
            newNode = node.cloneNode(true);

        pnode.replaceChild(newNode, node);
    }
};

See Matt Snider's post for an explanation of how this works.

As of 2022, there is a new approach to that task, this is CSS rule line-clamp, which basically tells how many lines should be kept and all the rest will be trimmed. Below is an example, where you can drag the corner and experiment with dimensions of the div.

  #resizable { 
  width: 400px; 
  height: 150px; 
  padding: 0 20px; 
  }
  
.wrapper {
border: 1px solid #dddddd;
background: #ffffff;
color: #333333;
position: relative;
}

.slider-text-wrapper p, .slider-text-wrapper .h1 {
    width: 100%;
    word-break: break-all;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -moz-box-orient: vertical;
    -ms-box-orient: vertical;
    box-orient: vertical;
    -webkit-line-clamp: 4;
    -moz-line-clamp: 4;
    -ms-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
}
.slider-text-wrapper .h1 {
    -webkit-line-clamp: 2;
    -moz-line-clamp: 2;
    -ms-line-clamp: 2;
    line-clamp: 2;
    font-size: 20px;
    margin: 10px 0;
}
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">

  
  <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
  <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
  
  <script>
  $( function() {
    $( "#resizable" ).resizable();
  } );
  </script>
  
<div id="resizable" class="ui-widget-content wrapper">
<div class="slider-text-wrapper">
<p class="h1">Example headline with surplus of words without any meaning, for just mere demonstration of html and css</p>
<p class="slider-text-intro">Some representative placeholder content for the first slide of the carousel. Some representative placeholder content for the first slide of the carousel. Some representative placeholder content for the first slide of the carousel. Some representative placeholder content for the first slide of the carousel.</p>
</p>
</div>

Related