1

In a generated html page, we have a fixed size area (lets say 200 x 300) in which we need to fit in as much text as possible (like a regular paragraph of text), and if it doesn't fit, remove an appropriate number of characters and append "..." to the end.

The text is NOT in a fixed sized font, and although we are using one specific font for this text, a "generic" solution would obviously be preferred.

This looked interesting, but I'm thinking it would be very slow with this function being called for several items on a page - http://bytes.com/topic/javascript/answers/93847-neatly-truncating-text-fit-physical-dimension

The solution can use an intermix of html, css, js, and php as needed.

Suggestions on approaches are more than welcome!

tzmatt7447
  • 2,329
  • 9
  • 24
  • 31

2 Answers2

1

Set the element dimensions via CSS and its overflow to "hidden".

Then, find out with this function, if the element's content is overflowing (via):

// Determines if the passed element is overflowing its bounds,
// either vertically or horizontally.
// Will temporarily modify the "overflow" style to detect this
// if necessary.
function checkOverflow(el)
{
   var curOverflow = el.style.overflow;
   if ( !curOverflow || curOverflow === "visible" )
      el.style.overflow = "hidden";

   var isOverflowing = el.clientWidth < el.scrollWidth 
      || el.clientHeight < el.scrollHeight;

   el.style.overflow = curOverflow;

   return isOverflowing;
}

Now, in a loop remove text and check until it is not overflowing anymore. Append an ellipsis character (String.fromCharCode(8230)) to the end, but only if it was overflowing.

To avoid any flickering effects during that operation, you can try working on a hidden copy of the element, but I'm not sure if the browsers do the necessary layout calculations on an element that's not visible. (Can anyone clarify that?)

Community
  • 1
  • 1
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • 1
    Wait a second... that's a SO question! Better to link to the actual question http://stackoverflow.com/questions/143815 – Yi Jiang Sep 10 '10 at 12:21
  • @Yi: Thanks for the cross link. :-) – Tomalak Sep 10 '10 at 12:22
  • :( :( :( - isnt there an 'elegant' way of doing this ...? Dont mind doing some maths to figure out what would work... – tzmatt7447 Sep 10 '10 at 12:41
  • Isnt there some html/css table setting that sets the width to be fixed and it does not move at all (cutting off the remaining text)? – tzmatt7447 Sep 10 '10 at 12:42
  • @tzmatt For your first question: It's not possible to predict the height of the elements until it is rendered on the page by the browser itself. For the second one, you're looking at `overflow: hidden`, although the phrasing in your question precludes that option. – Yi Jiang Sep 10 '10 at 12:50
  • @tzmatt: If you set the width and/or height in CSS, it *will* "not move at all". Regarding "elegant"… Layout is hard, especially in HTML. Let the browser do that, and deal with what is reality afterwards. Internet Explorer supports `overflow: ellipsis;` which pretty much is exactly what you want, and a pretty smart addition to the standard if you ask me, but the setting is not cross-browser compatible unfortunately. – Tomalak Sep 10 '10 at 13:02
1

I'd say that the solution you found is the best. It is, for instance, used for this jQuery plugin which autoresizes textareas as you enter text into it. I took the concept and rewrote it with jQuery for this simple test here: http://jsfiddle.net/ZDr5K/

var para = $('#para');
var height = 200;

while(para.height() >= height){
    var text = para.text();

    para.text(text.substring(0, text.length - 4) + '...');
}

Possible improvements would include right trimming and removing the period if the last character is a full stop. Removing word by word would also be more readable/slightly faster.

As for the function running multiple times, that would be unavoidable. The only thing you can really do with CSS here is to use :after to append the ellipses, but even that should be avoided for cross-compatibility problems.

Yi Jiang
  • 49,435
  • 16
  • 136
  • 136