In HTML 5, you can just use the Canvas.measureText method (further explanation here).
Try this fiddle:
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
*
* @param {String} text The text to be rendered.
* @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
*
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
function getTextWidth(text, font) {
// re-use canvas object for better performance
const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
const context = canvas.getContext("2d");
context.font = font;
const metrics = context.measureText(text);
return metrics.width;
}
function getCssStyle(element, prop) {
return window.getComputedStyle(element, null).getPropertyValue(prop);
}
function getCanvasFontSize(el = document.body) {
const fontWeight = getCssStyle(el, 'font-weight') || 'normal';
const fontSize = getCssStyle(el, 'font-size') || '16px';
const fontFamily = getCssStyle(el, 'font-family') || 'Times New Roman';
return `${fontWeight} ${fontSize} ${fontFamily}`;
}
console.log(getTextWidth("hello there!", "bold 12pt arial")); // close to 86
If you want to use the font-size of some specific element myEl
, you can make use of the getCanvasFontSize
utility function:
const fontSize = getTextWidth(text, getCanvasFontSize(myEl));
// do something with fontSize here...
Explanation: The getCanvasFontSize
function takes some element's (by default: the body
's) font and converts it into a format compatible with the Context.font property. Of course any element must first be added to the DOM before usage, else it gives you bogus values.
el.remove()); // hackfix: don't do this!
return el;
}
console.log(getTextWidth(
"hello there!",
getCanvasFontSize(createEl('span'))
));
console.log(getTextWidth(
"hello there!",
getCanvasFontSize(createEl('h1'))
));
``` -->
More Notes
There are several advantages to this approach, including:
- More concise and safer than the other (DOM-based) methods because it does not change global state, such as your DOM.
- Further customization is possible by modifying more canvas text properties, such as
textAlign
and textBaseline
.
NOTE: When you add the text to your DOM, remember to also take account of padding, margin and border.
NOTE 2: On some browsers, this method yields sub-pixel accuracy (result is a floating point number), on others it does not (result is only an int). You might want to run Math.floor
(or Math.ceil
) on the result, to avoid inconsistencies. Since the DOM-based method is never sub-pixel accurate, this method has even higher precision than the other methods here.
According to this jsperf (thanks to the contributors in comments), the Canvas method and the DOM-based method are about equally fast, if caching is added to the DOM-based method and you are not using Firefox. In Firefox, for some reason, this Canvas method is much much faster than the DOM-based method (as of September 2014).
Performance
This fiddle compares this Canvas method to a variation of Bob Monteverde's DOM-based method, so you can analyze and compare accuracy of the results.