如何计算平均字符宽度

How is average character width calculated

根据 HTML specificationcols 属性指定每行预期的最大字符数。

当使用的字体每个字符的宽度都相同时,情况就是如此。

根据w3schoolscols 属性指定文本区域的宽度(平均字符宽度)。

我猜它们是指字体的平均字符宽度,而不是文本区域中文本的平均字符宽度。

现在我的问题是用户代理如何计算某种字体的平均字符宽度,这个计算中包括哪些字符,...有没有办法我可以得到这个信息还是自己计算?

我想做的:计算文本区域内的 visual 行数,不使用除 textContent 和 cols 属性之外的任何其他内容。

我已经尝试过的:

const textSpan = document.getElementById("textSpan");
const textarea = document.getElementById("textarea");

textarea.addEventListener("input", (evt) => {
  textSpan.innerText = evt.target.value;
  console.log("Predicted number of lines: " + (textSpan.getBoundingClientRect().width / (textSpan.getBoundingClientRect().width / textSpan.innerText.length * 10))) // 10 = cols attribute of textarea element;
});
<textarea id="textarea" cols="10" rows="10" style="word-break: break-all;"></textarea>
<span id="textSpan"></span>

const textSpan = document.getElementById("textSpan");
const textSpanACW = document.getElementById("textSpanACW");
const textarea = document.getElementById("textarea");

textarea.addEventListener("input", (evt) => {
  textSpan.innerText = evt.target.value;
  console.log("Predicted number of lines: " + (textSpan.getBoundingClientRect().width / (textSpanACW.getBoundingClientRect().width / textSpanACW.innerText.length * 10))) // 10 = cols attribute of textarea element;
});
<textarea id="textarea" cols="10" rows="10" style="word-break: break-all;"></textarea>
<span id="textSpanACW">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,;?.:/=+ù%µ£^¨$*-_)àç!è§('"é&|@#¼½^{[{}</span>
<span id="textSpan"></span>

一旦我弄清楚了这一点,我就必须在不使用 word-break: break-all; 的情况下获得视线的数量。所以在答案中有这个很好,但不需要。

进一步阅读HTML specificationtextarea元素的textarea有效宽度为size×avg + sbw,其中size为元素的字符宽度,avg为元素的平均字符宽度元素的主要字体,以 CSS 像素为单位,sbw 是滚动条的宽度,以 CSS 像素为单位。 (元素的字母间距 属性 不影响结果。).

所以平均字符宽度(avg)的计算公式为:(effectiveWidth - sbw) / size.

获得sbw:

<style>
    /* way the hell off screen */
    .scrollbar-measure {
        width: 100px;
        height: 100px;
        overflow: scroll;
        position: absolute;
        top: -9999px;
    }
</style>
<script>
    const sbw = getScrollbarWidth();

    function getScrollbarWidth() {
        let scrollDiv = document.createElement("div");
        scrollDiv.className = "scrollbar-measure";
        document.body.appendChild(scrollDiv);
        const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
        document.body.removeChild(scrollDiv);
        return scrollbarWidth;
    }

</script>

获取尺寸:

HTML specification中:cols 属性指定每行预期的最大字符数。如果指定了 cols 属性,则其值必须是大于零的有效非负整数。如果将解析非负整数的规则应用于属性的值,结果是一个大于零的数字,则元素的字符宽度就是该值;否则为 20.

所以:

let size = parseInt(textarea.getAttribute("cols"));

if (isNaN(size)) {
    size = 20;
}

获取有效宽度:

如果元素具有 cols 属性,并且使用解析非负整数的规则解析该属性的值不会产生错误,则用户代理应将该属性用作元素宽度 属性 的表示提示,值为文本区域有效宽度(定义如下)。否则,用户代理应该表现得好像它具有用户代理级样式 sheet 规则,将元素上的宽度 属性 设置为文本区域的有效宽度。

所以:

const effectiveWidth = parseFloat(getComputedStyle(textarea).getPropertyValue("width").slice(0, -2));