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;
Community
  • 1
  • 1
JohWies
  • 107
  • 1
  • 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? – Toby May 14 '17 at 15:29
  • @Toby I'm trying to position another element at that position, yes. – JohWies May 14 '17 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. – JohWies May 14 '17 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. https://codepen.io/mcoker/pen/ybEyrL – Michael Coker May 14 '17 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...) – zer00ne May 14 '17 at 21:28
  • Possible duplicate of [how to calculate width and height of each character in a span](https://stackoverflow.com/questions/13408162/how-to-calculate-width-and-height-of-each-character-in-a-span) – Liam May 22 '18 at 09:14

2 Answers2

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();
};
Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81
  • 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! :) – Rachel Gallen May 14 '17 at 16:31
  • Thanks! I tried it out and it seems to be working perfectly! Thank you so much for your help. – JohWies May 14 '17 at 16:53
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>
see
  • 388
  • 4
  • 13
  • 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. – mesqueeb Nov 20 '22 at 05:30