4

I would like to get the width of a character for calculating the position of any given character (in pixels) inside a string. I figure this would be easy since I am using a monospace font but I have a problem.

I have tried the suggestions in this answer but this doesn't work for large strings. The precision is too poor which means that it works and I can get the position of the first few characters in the string but after, say 10 characters, the precision is so bad that the position I get for the character is so far off it's actually giving the position of the character before.

What I would like to do is get the width of a character so I can just write something like this:

var charWidth = ???;
var position = 5; // Shuold get the position of the fifth character in the string
var calculatedPosition = charWidth * position;
6
  • Having trouble suggesting a solution because I'm not entirely clear what you're trying to do - is the goal to position an HTML element based on the position of a character in a string? Or insert something at that point in the string? Commented May 14, 2017 at 15:29
  • @Toby I'm trying to position another element at that position, yes. Commented May 14, 2017 at 15:35
  • @RachelGallen The answer to the linked question, that I would create a hidden div with a string that I then use to calculate a character width. Commented May 14, 2017 at 15:36
  • I'm working on it but is this what you're running into? Looks like the width of the character here is 9.6px (per the dev tools in chrome) but clientWidth return 10px. So it's accurate-ish, but does break down with longer strings. codepen.io/mcoker/pen/ybEyrL Commented May 14, 2017 at 15:53
  • Why don't you just use .childNodes()? It's accurate because it doesn't care about width, fonts, or chars, it's only concern are nodes (e.g. elements, text, etc...) Commented May 14, 2017 at 21:28

2 Answers 2

4

Try this solution, developed by Ben Ripkens

CSS:

.textDimensionCalculation {
    position: absolute;
    visibility: hidden;
    height: auto;
    width: auto;
    white-space: nowrap;
}

JS:

var calculateWordDimensions = function(text, classes, escape) {
    classes = classes || [];

    if (escape === undefined) {
        escape = true;
    }

    classes.push('textDimensionCalculation');

    var div = document.createElement('div');
    div.setAttribute('class', classes.join(' '));

    if (escape) {
        $(div).text(text);
    } else {
        div.innerHTML = text;
    }

    document.body.appendChild(div);

    var dimensions = {
        width : jQuery(div).outerWidth(),
        height : jQuery(div).outerHeight()
    };

    div.parentNode.removeChild(div);

    return dimensions;
};

On his blog he writes

With the help of this little snippet we can now calculate the text dimensions like this.:

var dimensions = calculateWordDimensions('42 is the answer!'); <!--obviously a hitchhikers guide fan, lol --->

console.log(dimensions.width);
console.log(dimensions.height);

An alternate [jquery] solution has been written also by Phil Freo

$.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();
};
Sign up to request clarification or add additional context in comments.

2 Comments

obviously you don't have to write the dimensions to the console .. use them for whatever calcs you require .. but i thought his comment was funny! :)
Thanks! I tried it out and it seems to be working perfectly! Thank you so much for your help.
0

Here's a native javascript solution:

What we do is we create an element with a width of 1ch. ch is a css unit that denotes the width of the 0 character of the font. For monospaced fonts, this would be the width of all characters.

// An optional parent element that uses the required font family and size can be specified.
const singleCharacterWidth = (parent = document.body) => {

  const span = document.createElement("span");
  span.style.width = "1ch";
  span.style.position = "fixed";
  
  // The font family and font size can also directly be specified
  // span.style.fontFamily = "Source Code Pro";
  // span.style.fontSize = "24px";

  parent.appendChild(span);
  const width = span.getBoundingClientRect().width;
  parent.removeChild(span);

  return width;
};

const singleCharacterWidth = (parent = document.body) => {
  const span = document.createElement("span");
  span.style.width = "1ch";
  span.style.position = "fixed";

  parent.appendChild(span);
  const width = span.getBoundingClientRect().width;
  parent.removeChild(span);

  return width;
};

const snippetElem = document.querySelector(".snippet");

const charWidth = singleCharacterWidth(snippetElem);

console.log("Single character width:", charWidth)

// Multiplying the width of a single character by the length of the text
// should be equal (or very close) to the computed length of the element
console.log("width * length :", charWidth * snippetElem.innerText.length);
console.log("computed length:", snippetElem.getBoundingClientRect().width);
.snippet {
  font-family: monospace;
}
<span class="snippet">This is a snippet of text</span>

1 Comment

The thing to be careful about is that mono fonts don't use the same width for all characters. Eg. ア (Japanese A) is a different width from A, and ア (Japanese half width A) is again a different width from both of those.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.