Calculating text width

Here's a function that's better than others posted because

  1. it's shorter
  2. it works when passing an <input>, <span>, or "string".
  3. it's faster for frequent uses because it reuses an existing DOM element.

Demo: http://jsfiddle.net/philfreo/MqM76/

// Calculate width of text from DOM element or string. By Phil Freo <http://philfreo.com>
$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
    $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};

This worked better for me:

$.fn.textWidth = function(){
  var html_org = $(this).html();
  var html_calc = '<span>' + html_org + '</span>';
  $(this).html(html_calc);
  var width = $(this).find('span:first').width();
  $(this).html(html_org);
  return width;
};

The textWidth functions provided in the answers and that accept a string as an argument will not account for leading and trailing white spaces (those are not rendered in the dummy container). Also, they will not work if the text contains any html markup (a sub-string <br> won't produce any output and &nbsp; will return the length of one space).

This is only a problem for the textWidth functions which accept a string, because if a DOM element is given, and .html() is called upon the element, then there is probably no need to fix this for such use case.

But if, for example, you are calculating the width of the text to dynamically modify the width of an text input element as the user types (my current use case), you'll probably want to replace leading and trailing spaces with &nbsp; and encode the string to html.

I used philfreo's solution so here is a version of it that fixes this (with comments on additions):

$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').appendTo(document.body);
    var htmlText = text || this.val() || this.text();
    htmlText = $.fn.textWidth.fakeEl.text(htmlText).html(); //encode to Html
    htmlText = htmlText.replace(/\s/g, "&nbsp;"); //replace trailing and leading spaces
    $.fn.textWidth.fakeEl.html(htmlText).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};

My solution

$.fn.textWidth = function(){
    var self = $(this),
        children = self.children(),
        calculator = $('<span style="display: inline-block;" />'),
        width;

    children.wrap(calculator);
    width = children.parent().width(); // parent = the calculator wrapper
    children.unwrap();
    return width;
};

Basically an improvement over Rune's, that doesn't use .html so lightly

Tags:

Jquery