There are many situations while developing websites when you need to know how long a text string is: not how many characters it has but how long it is in pixels. While this isn't of much importance for regular webdesign it might get useful in certain scenario's like for example when designing Vista Sidebar gadgets.
To provide the experience as originally designed, you want to precisely position all elements within the gadget. While it isn't really difficult in case of static text, properly displaying dynamic content within the limited space on a Sidebar gadget might get quite challenging. Having the possibility to determine the visual length of the text string provides you greater flexibility while designing dynamic Sidebar gadgets.
The most common scenario I have faced was properly displaying a text string within limited space. If the string is visually longer than the available space it has to be visually trimmed. To let the user know that the text was trimmed … (three dots) are appended to the string.
In order to handle the situation described above you will need a few things:
- a hidden container (further called ruler) which will be used for loading the text. The font of that container must be the same as of the container which will eventually display the text
- a function for measuring the visual length of a text string
- a function for visually trimming the text to the desired length in pixels
The Ruler
Creating a ruler is really simple. All you need to do is to put
<span id="ruler"></span>
right under the <body> element and add to your CSS the following definition:
#ruler { visibility: hidden; white-space: nowrap; }
Measuring the visual length of a string
The next step is to create a function which will measure the length of a text in pixels:
String.prototype.visualLength = function() { var ruler = $("ruler"); ruler.innerHTML = this; return ruler.offsetWidth; }
First of all the function retrieves the reference to the ruler element. For the brevity I have chosen to use a simplified version of the document.getElementById JavaScript function:
function $(id) { return document.getElementById(id); }
Then the string is being set as the contents of the ruler element. After that the offsetWidth property contains the width in pixels of the ruler element which adjusts itself to fit the text.
While you could create a simple function which would take one parameter I have decided to benefit of the possibility of extending JavaScript classes using the prototype namespace. Having defined the function as above you can now retrieve the length of any string by calling:
var s = "Some text"; var len = s.visualLength();
Visually trimming the text
The last step is to trim the string to the given number of pixels:
String.prototype.trimToPx = function(length) { var tmp = this; var trimmed = this; if (tmp.visualLength() > length) { trimmed += "..."; while (trimmed.visualLength() > length) { tmp = tmp.substring(0, tmp.length-1); trimmed = tmp + "..."; } } return trimmed; }
Once again I have chosen to extend the String class so that the trimToPx method can be used on any string. What this function does is, it compares the visual length of a string with the length passed as parameter of the function. If the string is longer, it removes the last char from the string until the string fits in the given length. Additionally, to let the user know that the string has been trimmed, … (three dots) are appended to the string.

















January 1st, 2009 at 5:00 am
I am having trouble placing a context on the code that I have read above. I would like to understand/rather know how to implement the code. I understood the "Ruler" section, but then I got sorta ike mass confusion.
January 1st, 2009 at 3:03 pm
@bartieisaacm: do you have any JavaScript experience? Are there any particular pieces which you don't understand or is it all black magic?
March 11th, 2009 at 4:44 am
Waldek,
Thank you for this article. I needed to trim text to fit a fixed-width table cell without wrapping and this really did the trick.
I did run into one interesting wrinkle that I thought you might find interesting. My code is running in a SharePoint Content Editor Web Part. Oddly, when I define the span tag in the CEWP, ruler.offsetWidth returns zero but only when you are using IE. The code works fine in Firefox, and works with both browsers when loaded in a plain HTML file. Only the combination of CEWP and IE returns zero. Both Microsoft products. Huh.
I also include some common javascript functions in a script file loaded at page load time, high in the master page. I added a load-time document.write to define the ruler at load time, moving its definition out of the content template. My CEWP-resident code sets the span's font face and size during initialization. The string method extensions you provided in the article work fine now, returning good length values and properly trimming my strings.
Sometimes, when working with SharePoint, you have to take the long road home. At least we usually get there. That's a comfort.
Thanks again,
Dave
March 11th, 2009 at 8:13 am
@Dave Shaw: great to hear I could help, thank you for the feedback. It's not the first time that there is a difference between how IE and the rest of the world interpret JavaScript. Have you actually experienced the issue with IE6 or newer? With recent versions of IE going more and more towards standards it shouldn't be a problem anymore soon.
May 18th, 2010 at 1:26 pm
Does this work with spaces and tabulations ? It seems not to me.
May 19th, 2010 at 6:35 am
@Yacine: it doesn't since HTML doesn't 'understand' multiple spaces and tabs.
August 17th, 2010 at 9:28 am
works like a dream! Very nice.
October 27th, 2010 at 2:05 pm
This is excellent and working fine…
but im facing some problem and im clueless.
im using a html dialog to show the youtube video results in a grid, after selecting a video and inserting this vidoe into another window is spoiling the embed object code. Without your trimming func all, its working fine. any thoughts?
October 27th, 2010 at 9:21 pm
@srinivas: does the trimming break the code or the measuring itself?
December 2nd, 2010 at 12:03 pm
This is very good code.
But the trimming text function enters in infinite loop if the requested pixel length is higher than the three dots pixel length.
I agree that this case is highly improbable, but hey it happened to me :)
So to prevent that from happening, I inserted a single line code to return an empty string.
tmp = tmp.substring(0, tmp.length-1);
if(tmp == "") return ""; // Return empty string
trimmed = tmp + "…";
Thank you.
December 2nd, 2010 at 3:14 pm
@gsimo: Thanks for the tip :)
December 2nd, 2010 at 4:06 pm
Hi Waldek,
I Think this article could be handly for some stuff I´m working on,
I need to know how much pixels does a certain String, so I do (This is only a test):
String.prototype.VisualLength() = function()
{
var ruler = window.document.getElementById("ruler");
ruler.innerHTML = this;
return ruler.offsetWidth;
}
function prueba()
{
var s="This is a very largue text.";
var Length = s.VisualLength();
alert(Length) —-> return 122 down my question
//I´ve understand than this 122 value is the quantity of pixels than should have
// an input object by showing all the context of the string s without trimming
// ¿is that right? or may i miss understand the article.
window.document.getElementById("myinputobject").style.width = Length;
window.document.getElementById("myinputobject").value = s;
//The input object only shows: This is a very largue
}
the fuction prueba runs on the onclick event of the inputobject.
What I´m searching for is the quantity of pixels than I should give for example to a input object or a select object to fix exactly his width with the length of the text than contains.
¿is that possible?
March 3rd, 2011 at 3:44 pm
How about calculating a string length (in pixels) when the string is displayed in a certain font ??
March 3rd, 2011 at 3:52 pm
@Andrew: I think that's already there: the only thing that you would need to add is to set the font for the ruler div using JavaScript.
March 4th, 2011 at 5:39 pm
Waldek,
Dzieki za odpis. I didn't know that there're functions like: 'offsetWidth' in JS that give you width in pixels.
Thanks (dziekuje), Andrzej.
P.S: Do you speak any Polish (as your name may suggest) ??
March 5th, 2011 at 4:23 pm
@Andrew: you're welcome, and yes I do speak Polish :)
March 6th, 2011 at 6:45 pm
Thanks. I'm designing a simple horizontal navigation menu that contains anchors. I wanted to set the positioning of each anchor myself, so in the future I may be able to do a carousel or other animation. I was having trouble centering each text string of the anchor until I came across this page. Your solution works for me. Thanks.
Question, being new to web programming and hearing about browser compatibility issues, can you say if this is a conservative solution or is there something more safe in terms of all browsers considered?
March 6th, 2011 at 9:02 pm
@jordan: I have tested it in the few most common browsers but unfortunately I cannot give you any guarantee it will work on any browser/os combination.
March 16th, 2011 at 3:46 pm
Great code, thanks. Worked first time for me in IE 7
April 8th, 2011 at 5:21 am
Hi Waldek,
Can you put all parts together to see working example of this ?
I tried link them to all but not functioning as expected.
Thanks.
April 8th, 2011 at 1:17 pm
@ak: here you go. This will display the length of the "Some text" text.
<html>
<head>
<script type="text/javascript">
function $(id) {
return document.getElementById(id);
}
String.prototype.visualLength = function() {
var ruler = $("ruler");
ruler.innerHTML = this;
return ruler.offsetWidth;
}
</script>
</head>
<body>
<span id="ruler"></span>
<script type="text/javascript">
var s = "Some text";
var len = s.visualLength();
alert(len);
</script>
</body>
</html>
April 13th, 2011 at 8:52 am
This is very usual in the JavaScript app I'm creating. But, I need the height too. I'm placing text into a div. But, the div height is determined by the lines of text that it will contain. I tried "return ruler.offsetHeight". That's not the right height, because the div ends up being too small. I tried doubling it, but it will accumulate extra lines of pixes as text lines grows. You know how to get the actual height?
April 13th, 2011 at 10:01 am
oops, it is getting the right height. My problem is actuall the fact that the text wraps. I'm getting the visualLength of a string that may wrap several times inside a div. So, everytime it wraps, it increase this space left on the right margin to the total length the string occupies accumulatively. Now, I have to try to get that extra space it's adding.
April 13th, 2011 at 10:02 am
oops, it is getting the right height. My problem is actually the fact that the text wraps. I\'m getting the visualLength of a string that may wrap several times inside a div. So, everytime it wraps, it increase this space left on the right margin to the total length the string occupies accumulatively. Now, I have to try to get that extra space it\'s adding.
May 12th, 2011 at 8:29 am
Hi Waldek,
Can this be used to figure out the width of the text if it were bound in a rect of a certain width. That is to say, if the text is too large to fit in one line and spills over to multiple lines, is there a way that this can be modified to take care of that?
I tried passing a width parameter to the span (ruler.width = some px) in the function and also with different white-spacing options in the html tag but it doesn't seem to work.
Thanks!
Devang
May 18th, 2011 at 9:35 pm
@Devang: You could try to create a hidden container with the same text, compare its length to the length of the box and if it's longer extend the box. Would that work for you?
May 18th, 2011 at 9:42 pm
Thanks Waldek. I decided to work in svg text since I also wanted to do rotation which was not possible in only html. In that case, I think I will need to use a different method. However, if that doesn't work out, I'll try out what you suggested. I think that will work out.
July 29th, 2011 at 8:22 am
Ok, so after some tweaking to work with my ColdFusion site, this works perfect for me, except for one thing. Is there is a way to do it without that , because the way I have my site set up, that makes a line break, because it has to set to visibility: hidden; instead of display: none;
So, if there is any way you could remove the , I would be very grateful, seeing as how I have been pondering this, and trying to get rid of it myself for a few hours now, and it is now 1:22AM…
July 29th, 2011 at 8:25 am
Is it possible to remove the from this code? I only need to write the variable, and don't need to span the text anywhere after, but I have tried removing the <span and it breaks the code, and removing instances of ruler in the code also breaks it, I don't know why, because it doesn't seem linked to this ruler at all, other than to show the data there.
So, if you would be so kind, could you remove the need for the , which makes a line break on my site. All I need is the s and len variables to work.
July 29th, 2011 at 8:30 am
Oh, I forgot to mention, I have tried onload in the body tag, with code to set it to display: none; which works and lets the other code run, before hiding the span, but when it hides the span, the line break disappears abruptly and looks bad, that is why I would like the span gone all together.
July 29th, 2011 at 8:48 am
@Mitchell: I'm afraid that's the only method I know of. As far as I know you need the span to get the font and its size, etc.
July 29th, 2011 at 6:16 pm
Ok, well I though that. I went and was successfully able to place it elsewhere on the page, where it can never be seen, and I left the onload event in there, so just in case, it's remove when the page is done loading.
Thanks for your excellent code, no other examples I tried worked.
July 30th, 2011 at 5:03 am
i find that the character "f" is equal in pixel length with the character " " (the space), so if you just replace space with "f" you'll get an accurate width WITH spaces. I test it with '13px' AND '23px' font-sizes.
$('#ruler').html( $('#ruler').attr('value').replace(/ /g,'f');
December 30th, 2011 at 11:52 pm
Pretty awsome dude! thank you very much. I'm Braziliam but didn't find anything like that on our google answers. So I tried an English search and found your solution.
Just a little advice for the beginners: The number of pixels must be greater than 10, because the dots '…' have more than 10 pixels.
Thank you again Waldek!
January 1st, 2012 at 5:23 pm
@Matheus: Great to hear I could help. As for the number of pixels: wouldn't that depend on the size of the font?
January 1st, 2012 at 5:39 pm
yes, it depends on the size of the font.
thanks again!
January 31st, 2012 at 2:46 pm
The method in the article above is nice and easy to implement. But i think, it is not the best way to solve the problem of measuring.
One other way is to create – as the author already did – a element with the same properties as the source (cloneNode(true)) and hide it from the user by moving it to the far right, using transparent colors or something else.
The "trick" is to use the scrollLeft and scrollTop-Properties of this element to exactly measure the pixels, the text overflows. To do that, you have to set these properties to very large values (e.g. 99999). The browser corrects this and delivers the exact value which is equal or larger than zero.
But be aware: If the text is smaller, you wont be able to measure how much it is smaller with this method. If you want to do this, you should set the size to zero pixels and compare the result of scrollLeft/scrollTop with the dimensions of the source tag. For this you have to properly set whiteSpace and overflow to suit your needs – e.g.: if you want to measure only the X-axis, you should set whiteSpace = "nowrap" and overflow="hidden"
This works afaik in all modern browsers (modern = broadly used), with all fonts and is also very easy to implement.
Anyhow you should keep in mind that the created hidden element mus be added to the document node tree in order to get correct values. If do not do this, you may get strange results.