There are a few CSS features that Microsoft pioneered and has had available to developers in Internet Explorer for a long time now. One of those features is the text-overflow property, which is now in CSS3 and has implementations in Safari, and Opera. Firefox still does not support this feature, but I have heard that it will in Firefox 3.1.
Here is a rundown of what the property does. When text overflows an element’s box, the text-overflow property helps leave a visual hint to the user that there is more text. When a value of ellipsis is used, three dots will be shown before the text is clipped by overflow: hidden.
I wanted to be able to use this feature in all browsers, so I wrote a small jQuery plugin in order to support Firefox. You can download the plugin here. To use, just call ellipsis() on a jQuery object. For example:
$("span").ellipsis();
There is one option available, which is simply a boolean specifying whether or not to update the text when the size of the element changes. This is useful if the width of the element is a percent, or if you change it via javascript (although I wouldn’t recommend animation).
If you pass false or nothing at all, the text will remain static. If you know that the width of the element will not be changing, do not pass true. If you do, performance of the browser will decrease unnecessarily.
You can see a test page with the plugin here. The plugin will not do anything if you are not using Firefox.
If you are interested, take a look at the code. If you have a better solution that I have overlooked, or you can make it faster please comment here to let me know!
Update: Based on comments on Ajaxian, the plugin now no longer uses $.browser.mozilla, and instead uses feature testing.
Update: Based on Jimmie’s comment, the plugin should now work correctly with different fonts.
April 7, 2009 at 11:38 am
We developers can vote for this feature to be added to Firefox here:
https://bugzilla.mozilla.org/show_bug.cgi?id=312156
April 7, 2009 at 11:38 am
And, BTW, Firefox 3.1 will actually be Firefox 3.5
April 7, 2009 at 12:17 pm
Thanks for this! You’ve brought my attention to the text-overflow property I wasn’t aware of, and I’ve been playing with similar things to this recently such as elastic textareas which increase in height as your text overflows to a new line.
Very surprised Microsoft was behind the property and IE supports it where Firefox doesn’t! Makes a change…
We developers sure have quite a number of neat things we can do now to enhance usability.
I’ll be making use of this and taking a look at the code.
April 7, 2009 at 12:34 pm
Hi, I have just gone to the test page http://dl.getdropbox.com/u/534786/index.html and the second one does update when I resize the Safari window. Cheers,
April 7, 2009 at 1:03 pm
Here’s MichaelThompson comment at:
http://ajaxian.com/archives/text-overflow-for-firefox-via-jquery
..about this plugin:
“Because of the use of $.browser.mozilla in the plugin, this won’t work with jQuery 1.3.2+.”
Devon, can you use a useragent-detection jQuery plugin instead?
April 7, 2009 at 2:45 pm
@Pascal The plugin does not do anything at all in browsers other than Firefox since the property is supported natively. Therefore the second example will update when you resize your window in browsers other than Firefox.
Devon
April 7, 2009 at 10:50 pm
It should be a default feature for FF3.0
April 7, 2009 at 10:59 pm
jobs: Well, vote for it, and you’ll help make it a feature of Firefox 3.5 / 3.6.
April 8, 2009 at 5:21 am
Based on comments on Ajaxian (http://ajaxian.com/archives/text-overflow-for-firefox-via-jquery), I have updated the plugin so that it no longer uses $.browser.mozilla. I am working on some of the other issues now!
Thanks for the feedback!
Devon
April 8, 2009 at 8:56 pm
Definitely nice, though admittedly I haven’t needed to use the overflow feature as of yet – I’ve just never found a place where I wanted to implement it, to be honest, simply because I don’t like needing to scroll etcetera. Just my own thing. I can see where it would be useful in some cases, nevertheless.
April 10, 2009 at 7:46 am
Any chance of getting it to work when the browser is min/max’d? Not a big deal, really. Cool plugin.
April 11, 2009 at 3:27 pm
Will this work if the text goes across multiple lines and just show the ellipsis for the last line?
April 18, 2009 at 1:04 pm
Nice one devon. Good idea with the feature testing.
Was having some trouble getting it to work because the CSS of the element and _ellipsis_calc were not the same.
I changed it so that the ‘_ellipsis_calc’ element is inserted as a sibling element to the target, but hidden, and positioned absolutely. This lets the calc element receive most of the selectors the target would.
Additionally, instead of creating an arbitrary span, using jQuery.html (which ultimately uses .innerHTML (yuck!)), I’ve simplified this to use document.cloneNode.
Drawback is that I need to make a new calc element per each execution of ellipsis. But cloneNode has been proven to be surprisingly fast in all browsers. Here it is:
(function($) {
$.fn.ellipsis = function(enableUpdating){
var s = document.documentElement.style;
if (!(‘textOverflow’ in s || ‘OTextOverflow’ in s)) {
return this.each(function(){
var el = $(this);
if(el.css(“overflow”) == “hidden”){
var originalText = el.html();
var w = el.width();
var t = $(this.cloneNode(true)).css(‘position’, ‘absolute’).hide()
.css(‘width’, ‘auto’).css(‘overflow’, ‘visible’);
el.after(t);
var text = originalText;
while(text.length > 0 && t.width() > el.width()){
text = text.substr(0, text.length – 1);
t.html(text + “…”);
}
el.html(t.html());
t.remove();
if(enableUpdating == true){
var oldW = el.width();
setInterval(function(){
if(el.width() != oldW){
oldW = el.width();
el.html(originalText);
el.ellipsis();
}
}, 200);
}
}
});
} else return this;
};
})(jQuery);
April 18, 2009 at 1:07 pm
Here’s a cleaner version:
https://dl.getdropbox.com/u/8757/jquery.text-overflow.js
April 18, 2009 at 1:41 pm
Thanks for your comment Jimmie!
I was fooling around with cloning the element for the next release, but since you’ve already done the work for me, I’ve integrated your changes into the plugin.
There was one reason that I did not do this already, and that is because I didn’t want to recreate the element every time. But, I’ve ran a comparison of the speeds, and it is not noticeably slower. What I was doing was using the jQuery clone() function, which was not working for some reason!
Again, thanks!
Devon
April 28, 2009 at 10:40 am
Thanks for the nice code.
One question I have is if I would like to use it on a dynamic list of names in tapestry, how can I use it? I tried to give a id in the div for names, but only first is shown …, others would not display it though those names have the same id in the div.
May 3, 2009 at 6:12 pm
While not implemented in Gecko/Firefox, it’s at least well documented now
https://developer.mozilla.org/en/CSS/text-overflow
June 18, 2009 at 1:09 am
Great plugin, works great, the only thing I found is that when the width is constrained via a ‘max-width’ setting then it does not work (as the cloned element does not reset the max-width setting).
Appending
.css(‘max-width’, ‘inherit’)
to the list of css resets on the cloned element fixes the issue.
Thanks again for the nifty plugin.
June 18, 2009 at 10:50 am
That particular chain of code is getting a bit unwieldy, can be optimized and clarified with:
var t = $(this.cloneNode(true)).hide().css({
‘position’: ‘absolute’,
‘width’: ‘auto’,
‘overflow’: ‘visible’,
‘max-width’: ‘inherit’
});
Can’t remember why I placed ‘position: absolute’ before .hide() originally, but it probably doesn’t matter.
June 26, 2009 at 5:48 am
Great plugin, just what I was looking for. I added to my JS lib immediately :]
Adding
var replaceTags = new RegExp(/\s]+))?)+\s*|\s*)\/?>/igm);
el.attr(“alt”, originalText.replace(replaceTags, ”));
el.attr(“title”, originalText.replace(replaceTags, ”));
… adds the original text w/o any HTML tags as hover.
August 14, 2009 at 8:05 am
this does not work in FF3.5
August 14, 2009 at 8:09 am
@Michael It works just fine for me in Firefox 3.5. What is the problem that you are seeing?
August 14, 2009 at 8:37 am
I see the text w/o ellipsis – I can see it in 3 but not in 3.5 If you want, send am email to michael at echo3.net I will reply w/ a screen shot. The line ends with “amet, c” and the “c” is cut.
August 14, 2009 at 1:52 pm
The example above is the CSS3 property, text-overflow: ellipsis, which is known to be unsupported in in Firefox.
The point of this post was to demonstrate that, and provide an unobtrusive Javascript workaround. This page
http://dl.getdropbox.com/u/534786/index.html
should demonstrate the fix appropriately in Firefox.
August 24, 2009 at 5:17 am
Very nice solution indeed.
Here are 3 suggestions for improving the script:
1. For very long strings, it’s better to use a different approach for finding the place to put the ellipsis. For example, chop the last half from the string until it fits and then add one more until it does not fit anymore.
2. It’s better to display the ellipsis character instead of three dots. You can use ampersand-#x2026; for that.
3. When the remaining string ends with a space character (32 decimal or 20 hex), also remove that character. That’s consistent with how IE works. And it looks a lot better.
For #2 and #3, here’s a suggested code snippet, replacing the current while loop in your code:
while (textLength > 0 && t.width() > el.width()) {
textLength–;
text = text.substr(0, textLength);
while (text.charAt(textLength – 1) == ‘ ‘) {
textLength–;
text = text.substr(0, textLength);
}
t.html(text + “…”);
}
August 24, 2009 at 5:21 am
In the code snippet I posted, whitespace gets chopped off and a double minus-character becomes a single minus-character; d’oh.
Anyway, I forgot to mention that before the while loop I also cached the text length:
var textLength = text.length;
October 2, 2009 at 12:53 pm
Hello Devon,
thanks for sharing this nice script.
I made some changes a few days ago to improve the script execution time and I’d like to share them with you.
Here’s a patch with my changes:
http://pastebin.com/f7791ebdd
Thanks.
October 9, 2009 at 5:21 pm
Seems this is only a single line solution?
October 15, 2009 at 3:50 pm
http://pastebin.com/f6dec9e34
Here is another revision at this, it works with spans now by setting nowrap. It also uses a binary search of when calculating where to truncate a line. If your lines are generally more than a few characters longer than the box this is much more efficient.
October 15, 2009 at 4:06 pm
http://pastebin.com/f3f07f9a1
Actually that is a slight step better than my previous post. It reduces the loop iteration count by one in some cases and also reduces the number of method calls by using local variables where possible.
November 4, 2009 at 4:04 pm
We had a page with about 40 strings that needed ellipses, each of them coming down from about 200 chars to about 20. This was causing Firefox to pop up a dialog complaining about script performance.
So Alan Hensel and I added some performance fixes. The problem was that the strings were being truncated one character at a time. We fixed it by making an approximation of the length of the text, and then fine tuning it down to be as close as possible.
Feel free to grab the code or clone it from our gist: http://gist.github.com/226365
November 9, 2009 at 4:59 pm
I made some mods to support multiple lines and automatically adding some expansion links.
http://jeffmartin.com/journal/2009/11/9/a-custom-ellipsis-plug-in-for-jquery.html