I’ve done this in the past using jQuery. You can measure the size of a piece of text like this:
// txt is the text to measure, font is the full CSS font declaration,
// e.g. "bold 12px Verdana"
function measureText(txt, font) {
var id = 'text-width-tester',
$tag = $('#' + id);
if (!$tag.length) {
$tag = $('<span id="' + id + '" style="display:none;font:' + font + ';">' + txt + '</span>');
$('body').append($tag);
} else {
$tag.css({font:font}).html(txt);
}
return {
width: $tag.width(),
height: $tag.height()
}
}
var size = measureText("spam", "bold 12px Verdana");
console.log(size.width + ' x ' + size.height); // 35 x 12.6
In order to fit this to a given space, it’s a little trickier – you need to separate out the font-size
declaration and scale it appropriately. Depending on how you’re doing things, this might be easiest if you break out the different parts of the font
declaration. A resize function might look like this (again, obviously, this is jQuery-dependent):
function shrinkToFill(input, fontSize, fontWeight, fontFamily) {
var $input = $(input),
txt = $input.val(),
maxWidth = $input.width() + 5, // add some padding
font = fontWeight + " " + fontSize + "px " + fontFamily;
// see how big the text is at the default size
var textWidth = measureText(txt, font).width;
if (textWidth > maxWidth) {
// if it's too big, calculate a new font size
// the extra .9 here makes up for some over-measures
fontSize = fontSize * maxWidth / textWidth * .9;
font = fontWeight + " " + fontSize + "px " + fontFamily;
// and set the style on the input
$input.css({font:font});
} else {
// in case the font size has been set small and
// the text was then deleted
$input.css({font:font});
}
You can see this in action here: http://jsfiddle.net/nrabinowitz/9BFQ8/5/
Testing seems to show that this is a little jumpy, at least in Google Chrome, because only full-integer font sizes are used. You might be able to do better with a em
-based font declaration, though this might be a little tricky – you’d need to ensure that the 1em
size for the text width tester is the same as that for the input.