views:

13515

answers:

8

I'd like to use Javascript to calculate the width of a string, is this possibly without having to use a monospace typeface? If it's not built in my only idea is to create a table of widths for each character but this is pretty unreasonable especially supporting unicode and different type sizes (and all browsers for that matter).

Thanks for any ideas!

+25  A: 

Create a DIV styled with the following styles. In your JavaScript, set the font size and attributes that you are trying to measure, put your string in the DIV, then read the current width and height of the DIV. It will stretch to fit the contents and the size will be within a few pixels of the string rendered size.

HTML:

<div id="Test">
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>

CSS:

#Test
{
    position: absolute;
    visibility: hidden;
    height: auto;
    width: auto;
}

JavaScript (fragment):

var test = document.getElementById("Test");
test.style.fontSize = fontSize;
var height = (test.clientHeight + 1) + "px";
var width = (test.clientWidth + 1) + "px";
CMPalmer
it was quite the race ;)
mattlant
Yep. I had to go pull an old JS file out of SVN to get my sample...
CMPalmer
The only thing I'd add is that this may give the wrong dimensions depending on which styles are used. Remember you may have styles like p { letter-spacing: 0.1em; } that a DIV element would not reflect. You must ensure that the styles in place are appropriate for where you will use the text.
Jim
Ditto Jim's comment - double-check to make sure the container, div in this case, does not have any other styles applied to it via css selection rules that you may not be cognizant of at the time. Strip all relevant styles from the container before applying the ones you care about before measuring.
Jason Bunting
You should also put in white-space:nowrap if you think the text will exceed the browser width.
Herb Caudill
+1  A: 

This is just a guess(I am not very proficient with css and such, sorry), but could you put text in an element that grows with the text, and then measure that element?

mattlant
+2  A: 

Text

<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>

This should work as long as the <span> tag has no other styles applied to it. offsetWidth will include the width of any borders, horizontal padding, vertical scrollbar width, etc.

Bryan Friedman
+3  A: 

The ExtJS javascript library has a great class called Ext.util.TextMetrics that "provides precise pixel measurements for blocks of text so that you can determine exactly how high and wide, in pixels, a given block of text will be". You can either use it directly or view its source to code to see how this is done.

http://extjs.com/deploy/dev/docs/?class=Ext.util.TextMetrics

big lep
A: 

Awesome! Thank you!

+5  A: 

jQuery:

(function($) {

 $.textMetrics = function(el) {

  var h = 0, w = 0;

  var div = document.createElement('div');
  document.body.appendChild(div);
  $(div).css({
   position: 'absolute',
   left: -1000,
   top: -1000,
   display: 'none'
  });

  $(div).html($(el).html());
  var styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing'];
  $(styles).each(function() {
   var s = this.toString();
   $(div).css({
    s: $(el).css(s)
   });
  });

  h = $(div).outerHeight();
  w = $(div).outerWidth();

  $(div).remove();

  var ret = {
   height: h,
   width: w
  };

  return ret;
 }

})(jQuery);
Deepak Nadar
A: 

The code-snips below, "calculate" the width of the span-tag, appends "..." to it if its too long and reduces the text-length, until it fits in its parent (or until it has tried more than a thousand times)

CSS

div.places {
  width : 100px;
}
div.places span {
  white-space:nowrap;
  overflow:hidden;
}

HTML

<div class="places">
  <span>This is my house</span>
</div>
<div class="places">
  <span>And my house are your house</span>
</div>
<div class="places">
  <span>This placename is most certainly too wide to fit</span>
</div>

JavaScript (with jQuery)

// loops elements classed "places" and checks if their child "span" is too long to fit
$(".places").each(function (index, item) {
    var obj = $(item).find("span");
    if (obj.length) {
        var placename = $(obj).text();
        if ($(obj).width() > $(item).width() && placename.trim().length > 0) {
            var limit = 0;
            do {
                limit++;
                                    placename = placename.substring(0, placename.length - 1);
                                    $(obj).text(placename + "...");
            } while ($(obj).width() > $(item).width() && limit < 1000)
        }
    }
});
Techek
A: 

This works for me...

// Handy JavaScript to meature the size taken to render the supplied text;
// you can supply additional style information too if you have it to hand.

function measureText(pText, pFontSize, pStyle) {
  var lDiv = document.createElement('lDiv');

  document.body.appendChild(lDiv);

  if (pStyle != null) {
    lDiv.style = pStyle;
  }
  lDiv.style.fontSize = "" + pFontSize + "px";
  lDiv.style.position = "absolute";
  lDiv.style.left = -1000;
  lDiv.style.top = -1000;

  lDiv.innerHTML = pText;

  var lResult = {
   width: lDiv.clientWidth,
   height: lDiv.clienHeight
  };

  document.body.removeChild(lDiv);
  lDiv = null;

  return lResult;
}
Pete