我想使用JavaScript来计算字符串的宽度。如果不使用单行字体,这可能吗?

如果它不是内置的,我唯一的想法是为每个字符创建一个宽度表,但这是非常不合理的,特别是支持Unicode和不同的类型大小(以及所有浏览器)。


当前回答

在HTML 5中,你可以只使用Canvas。measureText方法(此处进一步解释)。

试试这把小提琴:

/**
  * 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 getCanvasFont(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

如果你想使用特定元素myl的字体大小,你可以使用getCanvasFont实用函数:

const fontSize = getTextWidth(text, getCanvasFont(myEl));
// do something with fontSize here...

解释:getCanvasFontSize函数接受某些元素的字体(默认为正文),并将其转换为与上下文兼容的格式。字体属性。当然,任何元素在使用之前都必须首先添加到DOM中,否则会给您虚假的值。

更多的笔记

这种方法有几个优点,包括:

比其他(基于DOM的)方法更简洁和更安全,因为它不改变全局状态,比如DOM。 进一步的定制可以通过修改更多的画布文本属性,如textAlign和textBaseline。

注意:当你在DOM中添加文本时,记住还要考虑到填充、边距和边框。

注2:在某些浏览器上,该方法产生亚像素精度(结果是浮点数),在其他浏览器上则不是(结果只是一个int)。你可能想运行数学。floor(或Math.ceil),以避免不一致。由于基于dom的方法从来没有亚像素精度,因此该方法比这里的其他方法具有更高的精度。

根据这个jsperf(感谢评论中的贡献者),如果将缓存添加到基于dom的方法中,并且您没有使用Firefox,那么Canvas方法和基于dom的方法几乎一样快。在Firefox中,由于某种原因,这种Canvas方法要比基于dom的方法快得多(截至2014年9月)。

性能

本文将此Canvas方法与Bob Monteverde基于dom的方法的变体进行了比较,因此您可以分析和比较结果的准确性。

其他回答

试试下面的代码:

function GetTextRectToPixels(obj)
{
var tmpRect = obj.getBoundingClientRect();
obj.style.width = "auto"; 
obj.style.height = "auto"; 
var Ret = obj.getBoundingClientRect(); 
obj.style.width = (tmpRect.right - tmpRect.left).toString() + "px";
obj.style.height = (tmpRect.bottom - tmpRect.top).toString() + "px"; 
return Ret;
}

我使用文本度量包。工作真的很好,我尝试了这个解决方案,但在某些原因,它计算错误。

textMetrics.init(document.querySelector('h1'), { fontSize: '20px' });

textMetrics.init({
  fontSize: '14px',
  lineHeight: '20px',
  fontFamily: 'Helvetica, Arial, sans-serif',
  fontWeight: 400,
  width: 100,
});

我猜这和Depak的条目很相似,但这是基于Louis Lazaris在impressiveweb页面上发表的一篇文章

(function($){

        $.fn.autofit = function() {             

            var hiddenDiv = $(document.createElement('div')),
            content = null;

            hiddenDiv.css('display','none');

            $('body').append(hiddenDiv);

            $(this).bind('fit keyup keydown blur update focus',function () {
                content = $(this).val();

                content = content.replace(/\n/g, '<br>');
                hiddenDiv.html(content);

                $(this).css('width', hiddenDiv.width());

            });

            return this;

        };
    })(jQuery);

fit事件用于在函数关联到控件之后立即执行函数调用。

例如:$(“输入”).autofit () .trigger(“适合”);

在HTML 5中,你可以只使用Canvas。measureText方法(此处进一步解释)。

试试这把小提琴:

/**
  * 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 getCanvasFont(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

如果你想使用特定元素myl的字体大小,你可以使用getCanvasFont实用函数:

const fontSize = getTextWidth(text, getCanvasFont(myEl));
// do something with fontSize here...

解释:getCanvasFontSize函数接受某些元素的字体(默认为正文),并将其转换为与上下文兼容的格式。字体属性。当然,任何元素在使用之前都必须首先添加到DOM中,否则会给您虚假的值。

更多的笔记

这种方法有几个优点,包括:

比其他(基于DOM的)方法更简洁和更安全,因为它不改变全局状态,比如DOM。 进一步的定制可以通过修改更多的画布文本属性,如textAlign和textBaseline。

注意:当你在DOM中添加文本时,记住还要考虑到填充、边距和边框。

注2:在某些浏览器上,该方法产生亚像素精度(结果是浮点数),在其他浏览器上则不是(结果只是一个int)。你可能想运行数学。floor(或Math.ceil),以避免不一致。由于基于dom的方法从来没有亚像素精度,因此该方法比这里的其他方法具有更高的精度。

根据这个jsperf(感谢评论中的贡献者),如果将缓存添加到基于dom的方法中,并且您没有使用Firefox,那么Canvas方法和基于dom的方法几乎一样快。在Firefox中,由于某种原因,这种Canvas方法要比基于dom的方法快得多(截至2014年9月)。

性能

本文将此Canvas方法与Bob Monteverde基于dom的方法的变体进行了比较,因此您可以分析和比较结果的准确性。

嘿,大家,我知道我来晚了一点,但我们开始吧

window.addEventListener("error",function(e){ alert(e.message); });
var canvas = new OffscreenCanvas(400, 50);
var ctx = canvas.getContext("2d");
ctx.font = "16px Ariel"; //this can be dynamic using getComputedStyle
const chars = ["a","b","c","d","e","f"," ","    "];
const charWidths = new Map();
while(chars.length > 0){
  var char = chars.shift();
  var wide = ctx.measureText(char).width;
  charWidths.set(char,wide);
}

然后你可以用它来做如下的事情:

var pixelWidth = charWidths.get("0");
//fyi css properties like letter-spacing need to be accounted for