我想使用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的方法的变体进行了比较,因此您可以分析和比较结果的准确性。

其他回答

这对我很有用……

// Handy JavaScript to measure the size taken to render the supplied text;
// you can supply additional style information too if you have it.

function measureText(pText, pFontSize, pStyle) {
    var lDiv = document.createElement('div');

    document.body.appendChild(lDiv);

    if (pStyle != null) {
        lDiv.style = pStyle;
    }
    lDiv.style.fontSize = "" + pFontSize + "px";
    lDiv.style.position = "absolute";
    lDiv.style.left = -1000;
    lDiv.style.top = -1000;

    lDiv.textContent = pText;

    var lResult = {
        width: lDiv.clientWidth,
        height: lDiv.clientHeight
    };

    document.body.removeChild(lDiv);
    lDiv = null;

    return lResult;
}

这是我随手拼凑的一个例子。看来我们都达成共识了。

String.prototype.width = function(font) {
  var f = font || '12px arial',
      o = $('<div></div>')
            .text(this)
            .css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
            .appendTo($('body')),
      w = o.width();

  o.remove();

  return w;
}

使用它很简单:"a string".width()

**增加了空格:nowrap,因此宽度大于窗口宽度的字符串可以被计算。

您可以使用max-content来测量文本的像素宽度。

这是一个效用函数。它可以选择将任何节点作为上下文来计算宽度,考虑到任何CSS,如字体大小、字母间距等。

function measureTextPxWidth( text, template = document.createElement("span") ) { const measurer = template.cloneNode(); measurer.style.setProperty("all", "revert", "important"); measurer.style.setProperty("position", "position", "important"); measurer.style.setProperty("visibility", "hidden", "important"); measurer.style.setProperty("width", "max-content", "important"); measurer.innerText = text; document.body.appendChild(measurer); const { width } = measurer.getBoundingClientRect(); document.body.removeChild(measurer); return width; } document.querySelector('.spanTextWidth').innerText = `${measureTextPxWidth('one two three')}px` document.querySelector('.h1TextWidth').innerText = `${measureTextPxWidth('one two three', document.querySelector('h1'))}px` h1 { letter-spacing: 3px; } <span>one two three</span> <div class="spanTextWidth"></div> <h1>one two three</h1> <div class="h1TextWidth"></div>

在文本的包含元素上使用scrollWidth来获得元素的最小宽度,包括由于溢出而隐藏的部分。更多信息请访问https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollWidth

如果元素不在DOM中,将其添加到某个隐藏区域以进行测量。例如:

function measureText(text) {
  let div = document.createElement("div");
  div.innerText = text;
  div.style.whiteSpace = 'nowrap';
  body.appendChild(div);
  let width = div.scrollWidth;
  body.removeChild(div);
  return width;
}

样式(字体大小、重量等)将被元素继承,因此计入宽度。您还可以使用scrollWidth和scrollHeight来测量更复杂内容的大小。

var textWidth = (function (el) {
    el.style.position = 'absolute';
    el.style.top = '-1000px';
    document.body.appendChild(el);

    return function (text) {
        el.innerHTML = text;
        return el.clientWidth;
    };
})(document.createElement('div'));