views:

521

answers:

6

In my (PHP) webapp, I have a part of my site that keeps a history of recent searches. The most recent queries get shown in a side box. If the query text is too long, I truncate it and show ellipses. Eg: "My very long query is..."

Currently, I truncate after a certain number of characters. Since the font is not monotype, a query of all I's is more narrow than a query of all W's. I'd like them to all be about the same width prior to the ellipses. Is there a way to get the approximate width of the resulting string so that the ellipses for any given string will occur in about the same number of pixels from the beginning? Does CSS have a way? Does PHP? Would this be better handled by JavaScript?

+2  A: 

Does CSS have a way?

No

Does PHP?

No

-

To do that you'd have to get the font metrics for each character, and apply them to all your letters in your string. While you could do this by using a drawing/rendering library like ImageMagick on the server, it wouldn't really work because different browser on different OS's render fonts differently.

Even if it did work, you wouldn't want to do it, because it would also take forever to render. Your server would be able to push 1 page per second (if that) instead of several thousand.

If you can live without the trailing ..., then you can nicely fake it using div tags and css overflow: hidden, like this:

.line_of_text {
    height:1.3em;
    line-height:1.3em;
    overflow:hidden;
}

<div class="line_of_text"> Some long text which will arbitrarily be cut off at whatever word fits best</div>
Orion Edwards
+6  A: 

Here's another take on it and you don't have to live without the ellipsis!

<html>
<head>

<style>
div.sidebox {
    width: 25%;
}

div.sidebox div.qrytxt {
    height: 1em;
    line-height: 1em;
    overflow: hidden;
}

div.sidebox div.qrytxt span.ellipsis {
    float: right;
}
</style>


</head>

<body>

<div class="sidebox">
    <div class="qrytxt">
     <span class="ellipsis">&hellip;</span>
     Some long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
    </div>
    <div class="qrytxt">
     <span class="ellipsis">&hellip;</span>
     Some more long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
    </div>
    <div class="qrytxt">
     <span class="ellipsis">&hellip;</span>
     Short text. Fail!
    </div>
</body>

</html>

There is one flaw with this, if the text is short enough to be fully displayed, the ellipses will still be displayed as well.

[EDIT: 6/26/2009]

At the suggestion of Power-Coder I have revised this a little. There are really only two changes, the addition of the doctype (see notes below) and the addition of the "display: inline-block" attribute on the qrytxt div. Here is what it looks like now...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
<html>
<head>
    <style>
        div.sidebox 
        {
            width: 25%;
        }

        div.sidebox div.qrytxt
        {
            height: 1em;
            line-height: 1em;
            overflow: hidden;
            display: inline-block;
        }

        div.sidebox div.qrytxt span.ellipsis
        {
            float: right;
        }
</style>
</head>

<body>
    <div class="sidebox">
        <div class="qrytxt">
            <span class="ellipsis">&hellip;</span>
            Some long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
        </div>

        <div class="qrytxt">
            <span class="ellipsis">&hellip;</span>
            Some more long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
        </div>

        <div class="qrytxt">
            <span class="ellipsis">&hellip;</span>
            Short text. FTW
        </div>
    </div>
</body>
</html>

Notes:

  • Viewed in IE 8.0, Opera 9, FF 3

  • A doctype is required for IE to get the "display: inline-block" to work correctly.

  • If the qrytxt div's overflow occurs on a long word, there is going to be a wide gap between the ellipsis and the last visible word. You can see this by viewing the example and resizing your browser width in small increments. (this probably existed in the original example as well, I just may have not noticed it then)

So again, an imperfect CSS-only solution. Javascript may be the only thing that can get the effect perfect.

[EDIT: 6/27/2009]

Here is another alternative which uses browser specific extensions.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;

<html>
<head>
    <style>
     div.sidebox 
     {
      width: 26%;
     }

     div.sidebox div.qrytxt
     {
      height: 1em;
      line-height: 1em;
      overflow: hidden;
      text-overflow:ellipsis;
      -o-text-overflow:ellipsis;
      -ms-text-overflow:ellipsis;
      -moz-binding:url(ellipsis-xbl.xml#ellipsis);
      white-space:nowrap;
     }
    </style>
</head>

<body>
    <div class="sidebox">
     <div class="qrytxt">
      Some long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
     </div>

     <div class="qrytxt">
      Some more long text which will arbitrarily be cut off at whatever word fits best but will have an ellipsis at the end.
     </div>

     <div class="qrytxt">
      Short text. FTW
     </div>
    </div>
</body>
</html>

Note that in order for the above example to work, you must create the xml file referenced by the -moz-binding rule, ellipsis-xbl.xml. It's should contain the following xml:

<?xml version="1.0" encoding="UTF-8"?>
  <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"&gt;
    <binding id="ellipsis">
      <content>
        <xul:window>
          <xul:description crop="end" xbl:inherits="value=xbl:text"><children/></xul:description>
        </xul:window>
      </content>
    </binding>
  </bindings>
Robert
I like this answer, we should look into updating it with a workaround for the short text issue. I'll see what I can do.
Wally Lawless
I've added an alternative. Still not perfect though :(
Robert
Here are two additional thoughts. First, use … for ellipsis, "..." is not the same as "…". Second, why all the floating spans to begin with? You can let the browser add the ellipsis to the div fully automatically when needed (by specifying text-overflow: ellipsis for IE, -o-text-overflow: ellipsis for Opera and using the -moz-binding workaround for FF).
RegDwight
@RegDwight: First, I've made the change to the hellip entity, thanks! Second, I used the floating spans because I (for better or worse) shy away from browser specific extensions (and therefore am not very familiar with them). I've looked into those you mentioned and in the spirit of completeness, am including a third alternative using those.
Robert
+2  A: 

@Robert

what if you put the ellipses in a div with a low z-index so that when it moves to the left (for shorter lines) they get covered up by a background image or something?

it's pretty hacky I know, but hey worth a try right?

edit Another idea: determine the position of the div containing the ellipses with javascript and if it's not pushed all the way right, hide it?

Jiaaro
+4  A: 

You could also quite easily use a bit of javascript:

document.getElementByID("qrytxt").offsetWidth;

will give you the width of an element in pixels and even works in IE6. If you append a span containing ellipses to the end of each query a simple logical test in JavaScript with a bit of CSS manipulation could be used to hide/show them as needed.

Evil Andy
+2  A: 

PHP should be left out of consideration completely due to the fact that even though there is a function designed for measuring fonts, http://www.php.net/imageftbbox , there is no way for PHP to know whether the visitor has a minimum font size setup that is larger than your anticipated font size.

joebert
A: 

An article on this: http://mattsnider.com/css/css-string-truncation-with-ellipsis/

Dinah