76

Is there any way to determine the pixel length of a string in jQuery/JavaScript?

0

8 Answers 8

63

The contexts used for HTML Canvases have a built-in method for checking the size of a font. This method returns a TextMetrics object, which has a width property that contains the width of the text.

function getWidthOfText(txt, fontname, fontsize){
    if(getWidthOfText.c === undefined){
        getWidthOfText.c=document.createElement('canvas');
        getWidthOfText.ctx=getWidthOfText.c.getContext('2d');
    }
    var fontspec = fontsize + ' ' + fontname;
    if(getWidthOfText.ctx.font !== fontspec)
        getWidthOfText.ctx.font = fontspec;
    return getWidthOfText.ctx.measureText(txt).width;
}

Or, as some of the other users have suggested, you can wrap it in a span element:

function getWidthOfText(txt, fontname, fontsize){
    if(getWidthOfText.e === undefined){
        getWidthOfText.e = document.createElement('span');
        getWidthOfText.e.style.display = "none";
        document.body.appendChild(getWidthOfText.e);
    }
    if(getWidthOfText.e.style.fontSize !== fontsize)
        getWidthOfText.e.style.fontSize = fontsize;
    if(getWidthOfText.e.style.fontFamily !== fontname)
        getWidthOfText.e.style.fontFamily = fontname;
    getWidthOfText.e.innerText = txt;
    return getWidthOfText.e.offsetWidth;
}

EDIT 2020: added font name+size caching at Igor Okorokov's suggestion.

Sign up to request clarification or add additional context in comments.

13 Comments

Some reason this is not working in Chrome 54 or Firefox 48. e.innerWidth keeps coming up as undefined.
You have to add this to the DOM for the width or height to be calculated. document.body.appendChild(e)
you're missing a space after the px when setting fontSize/face on the canvas
@Xenon I mean, if you just copy this snippet, it won't work since the 'px' + fontname is missing space after px.
canvas idea is awesome (especially if you alredy have one)! its pure js approach, its better than span, and does not require jquery
|
61

Wrap text in a span and use jquery width()

EDIT: jQuery is probably not the best solution anymore. Using plain JavaScript is an option, like seen on https://youmightnotneedjquery.com/#get_width:

el.getBoundingClientRect().width;

9 Comments

Don't forget: placement and styling of the div/span makes a difference, because wrapping can come into play.
This does only return the width of the containing element but not the width of the text.
Using a <span> wrapper works the best, because a <div> is automatically set to 100% browser width.
You should probably provide some sample code. I'm having a hard time figuring out exactly what you mean by "wrap text in a span". Should the span be in the original html? Can I create a dummy span that isn't seen? How at runtime? I tried: $('<span></span>').html('hi').width() but it output 0
I would add white-space: nowrap to the span element, otherwise if the text is wrapped because the container is too small you'll have a wrong result
|
11

I don't believe you can do just a string, but if you put the string inside of a <span> with the correct attributes (size, font-weight, etc); you should then be able to use jQuery to get the width of the span.

<span id='string_span' style='font-weight: bold; font-size: 12'>Here is my string</span>
<script>
  $('#string_span').width();
</script>

2 Comments

If you are worried about wrapping, ensure that your string contains non-breaking spaces: &nbsp; instead of a regular space.
@TopherFangio Or better, use css white-space: nowrap.
8

Based on vSync's answer, the pure javascript method is lightning fast for large amount of objects. Here is the Fiddle: https://jsfiddle.net/xeyq2d5r/8/

[1]: https://jsfiddle.net/xeyq2d5r/8/ "JSFiddle"

I received favorable tests for the 3rd method proposed, that uses the native javascript vs HTML Canvas

Google was pretty competive for option 1 and 3, 2 bombed.

FireFox 48:
Method 1 took 938.895 milliseconds.
Method 2 took 1536.355 milliseconds.
Method 3 took 135.91499999999996 milliseconds.

Edge 11 Method 1 took 4895.262839793865 milliseconds.
Method 2 took 6746.622271896686 milliseconds.
Method 3 took 1020.0315412885484 milliseconds.

Google Chrome: 52
Method 1 took 336.4399999999998 milliseconds.
Method 2 took 2271.71 milliseconds.
Method 3 took 333.30499999999984 milliseconds.

8 Comments

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
But it does provide further testing of the answers provided to clearly show how they perform. Ive always benefit from the comments and additional information like this in other posts. Thats why I added it, felt like the work I did should benefit others that see this post. Not like it doesnt have 56812 views in 6 years....
Sorry if it sounded rude, but that is not the way SO works. You may go through FAQ and understand further. We try to improve the quality of the posts, that is why certain posts are flagged.
This helped a lot. Checking the perf. of an implementation is very important when having to choose from multiple options, especially across browsers.
Method 3 returns undefined when logging the innerWidth.
|
6

Put it in an absolutely-positioned div then use clientWidth to get the displayed width of the tag. You can even set the visibility to "hidden" to hide the div:

<div id="text" style="position:absolute;visibility:hidden" >This is some text</div>
<input type="button" onclick="getWidth()" value="Go" />
<script type="text/javascript" >
    function getWidth() {
        var width = document.getElementById("text").clientWidth;
        alert(" Width :"+  width);
    }
</script>

Comments

3

First replicate the location and styling of the text and then use Jquery width() function. This will make the measurements accurate. For example you have css styling with a selector of:

.style-head span
{
  //Some style set
}

You would need to do this with Jquery already included above this script:

var measuringSpan = document.createElement("span");
measuringSpan.innerText = 'text to measure';
measuringSpan.style.display = 'none'; /*so you don't show that you are measuring*/
$('.style-head')[0].appendChild(measuringSpan);
var theWidthYouWant = $(measuringSpan).width();

Needless to say

theWidthYouWant

will hold the pixel length. Then remove the created elements after you are done or you will get several if this is done a several times. Or add an ID to reference instead.

Comments

0

Maybe it will useful for some

const getMaxPixelsOfStrings = ({ strings, styles = {} }) => {
  const spans = strings.map(str => {
    const span = document.createElement('span')
    span.append(str)
    Object.assign(span.style, {
      position: 'absolute',
      ...styles,
    })

    return span
  })

  document.querySelector('html').prepend(...spans)
  const maxPixels = Math.max(...spans.map(span => span.getBoundingClientRect().width))

  spans.forEach(span => span.remove())

  return maxPixels
}

usage

getMaxPixelsOfStrings({
            strings: ['One', 'Two', 'Three', 'Four', 'Five'],
            styles: {
              fontSize: '18px',
              letterSpacing: '1px',
            },
          })

Comments

-2

If you use Snap.svg, the following works:

var tPaper = Snap(300, 300);
var tLabelText = tPaper.text(100, 100, "label text");
var tWidth = tLabelText.getBBox().width;  // the width of the text in pixels.
tLabelText.attr({ x : 150 - (tWidth/2)});   // now it's centered in x

3 Comments

Being relatively inexperienced, I'd love to know why this was downvoted. Is it because it is a solution using Snap? It's what I use in order to avoid coping with canvas in JavaScript.
This is just what I was looking for but I'm getting zero in the width of the text...
The original answer used tPaper.node.clientWidth. Kuhaku couldn't get that to work, and dang! Now neither can I. I have altered the example to use .getBBox(). I think that you can use clientWidth on a Snap.svg "paper" object, the drawing surface (and getBBox() does not work); but for elements (circles, shapes, and importantly, text) you can use getBBox(). I have a demo in an answer to another post

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.