在Javascript中获取字符宽度

4
我想获取一个字符的宽度,以便计算字符串中任何给定字符(以像素为单位)的位置。我认为这很容易,因为我正在使用等宽字体,但我有一个问题。
我已经尝试了这个答案中提出的建议,但是对于较长的字符串,这并不起作用。精度太差了,这意味着它可以工作,并且我可以获得字符串中前几个字符的位置,但在10个字符之后,精度非常差,以至于我得到的字符位置偏离实际位置太远,实际上是给出前一个字符的位置。
我想做的是获取一个字符的宽度,以便我可以像这样编写代码:
var charWidth = ???;
var position = 5; // Shuold get the position of the fifth character in the string
var calculatedPosition = charWidth * position;

由于我不完全清楚您想要做什么,因此很难提出解决方案 - 您的目标是根据字符串中字符的位置来定位HTML元素吗?还是在字符串中的那个点插入一些内容? - Toby
@Toby 我正在尝试将另一个元素定位在那个位置。 - JohWies
@RachelGallen 我会创建一个带有字符串的隐藏div,然后使用它来计算字符宽度。 - JohWies
我正在处理这个问题,但是你遇到的是这个吗?看起来这里字符的宽度是 9.6px(根据 Chrome 开发工具),但是 clientWidth 返回 10px。所以它大致准确,但在较长的字符串中会出现问题。https://codepen.io/mcoker/pen/ybEyrL - Michael Coker
为什么不直接使用.childNodes()呢?它很准确,因为它不关心宽度、字体或字符,它只关心节点(例如元素、文本等...)。 - zer00ne
可能是如何计算span中每个字符的宽度和高度的重复问题。 - Liam
2个回答

4

尝试这个由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;
};

在他的博客上,他写道:

借助这个小片段,我们现在可以像这样计算文本尺寸:

var dimensions = calculateWordDimensions('42 is the answer!'); <!--obviously a hitchhikers guide fan, lol --->

console.log(dimensions.width);
console.log(dimensions.height);

Phil Freo也写了一个替代 [jquery] 解决方案

$.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
谢谢!我试过了,它似乎完美地运行了!非常感谢你的帮助。 - JohWies

0
这是一个原生JavaScript的解决方案:
我们所做的是创建一个宽度为1ch的元素。 ch是一个CSS单位,表示字体0字符的宽度。对于等宽字体,这将是所有字符的宽度。
// 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>


需要注意的是,等宽字体并不对所有字符使用相同的宽度。 例如,ア(日语的A)的宽度与A不同,而ア(日语半角A)的宽度与这两者又不同。 - mesqueeb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接