我想使用JavaScript来计算字符串的宽度,是否可以不使用等宽字体实现?
如果没有内置的方法,我的唯一想法是为每个字符创建一个宽度表,但这很不切实际,特别是支持Unicode和不同的字体大小(以及所有浏览器)。
我想使用JavaScript来计算字符串的宽度,是否可以不使用等宽字体实现?
如果没有内置的方法,我的唯一想法是为每个字符创建一个宽度表,但这很不切实际,特别是支持Unicode和不同的字体大小(以及所有浏览器)。
/**
* 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://dev59.com/EHVD5IYBdhLWcg3wAWsO#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
如果您想使用特定元素myEl
的字体大小,您可以使用getCanvasFont
实用函数:
const fontSize = getTextWidth(text, getCanvasFont(myEl));
// do something with fontSize here...
解释:函数getCanvasFontSize
获取某个元素(默认为)的字体并将其转换为与Context.font属性兼容的格式。 当然,任何元素在使用之前都必须先被添加到DOM中,否则它会给您提供虚假的值。
更多说明:
这种方法有几个优点,包括:
textAlign
和textBaseline
,可以进行进一步的自定义。注意2:在某些浏览器上,此方法可以提供亚像素精度(结果为浮点数),而在其他浏览器上则不行(结果仅为整数)。您可能需要对结果运行Math.floor
(或Math.ceil
)以避免不一致。由于基于DOM的方法永远不会达到亚像素精度,因此此方法甚至比这里介绍的其他方法具有更高的精度。
根据this jsperf(感谢评论中的贡献者),如果将缓存添加到基于DOM的方法中并且您没有使用Firefox,则Canvas方法和基于DOM的方法的速度大约相同。在Firefox中,由于某种原因,此Canvas方法比基于DOM的方法快得多(截至2014年9月)。
这个示例将这个Canvas方法与Bob Monteverde的基于DOM的方法的变体进行比较,因此您可以分析和比较结果的准确性。
strokeText()
或fillText()
才会影响画布。也许您想评论其他答案? - Ajedi32var fontSize = 12;
var test = document.getElementById("Test");
test.style.fontSize = fontSize;
var height = (test.clientHeight + 1) + "px";
var width = (test.clientWidth + 1) + "px"
console.log(height, width);
#Test
{
position: absolute;
visibility: hidden;
height: auto;
width: auto;
white-space: nowrap; /* Thanks to Herb Caudill comment */
}
<div id="Test">
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>
+1
是用来偏移计算的。 - Kip这是我没有示例就匆忙写出来的一个。看起来我们都在同一页上。
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()
**添加了white-space: nowrap
,以便可以计算窗口宽度大于字符串宽度的字符串。
String
中,因为它会破坏程序的“关注点分离”原则(即将核心代码和UI代码分开)。想象一下,如果你想将核心代码移植到一个使用非常不同的UI框架的平台上... - Domio[0].getBoundingClientRect().width
:https://dev59.com/vHA65IYBdhLWcg3w1SbU#16072668 - Alexander Olsson我喜欢你的“唯一思路”,即只做一个静态的字符宽度映射!对于我的目的来说,它实际上非常有效。有时候出于性能原因或者因为你无法轻松访问DOM,你可能只想要一个快速的、粗略的独立计算器来校准单个字体。所以这里有一个校准Helvetica的版本;传递一个字符串和字体大小:
const widths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.2796875,0.2765625,0.3546875,0.5546875,0.5546875,0.8890625,0.665625,0.190625,0.3328125,0.3328125,0.3890625,0.5828125,0.2765625,0.3328125,0.2765625,0.3015625,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.2765625,0.2765625,0.584375,0.5828125,0.584375,0.5546875,1.0140625,0.665625,0.665625,0.721875,0.721875,0.665625,0.609375,0.7765625,0.721875,0.2765625,0.5,0.665625,0.5546875,0.8328125,0.721875,0.7765625,0.665625,0.7765625,0.721875,0.665625,0.609375,0.721875,0.665625,0.94375,0.665625,0.665625,0.609375,0.2765625,0.3546875,0.2765625,0.4765625,0.5546875,0.3328125,0.5546875,0.5546875,0.5,0.5546875,0.5546875,0.2765625,0.5546875,0.5546875,0.221875,0.240625,0.5,0.221875,0.8328125,0.5546875,0.5546875,0.5546875,0.5546875,0.3328125,0.5,0.2765625,0.5546875,0.5,0.721875,0.5,0.5,0.5,0.3546875,0.259375,0.353125,0.5890625]
const avg = 0.5279276315789471
function measureText(str, fontSize) {
return Array.from(str).reduce(
(acc, cur) => acc + (widths[cur.charCodeAt(0)] ?? avg), 0
) * fontSize
}
那个巨大丑陋的数组是由字符代码索引的ASCII字符宽度。因此它只支持ASCII(否则会假定平均字符宽度)。幸运的是,宽度基本上与字体大小成线性比例关系,所以它在任何字体大小下都能很好地工作。它明显缺乏对字距或连字等的意识。
为了“校准”,我只需在svg上呈现每个字符直到charCode 126(强大的波浪号),然后获得边界框并将其保存到此数组中;更多代码、说明和演示请点击这里。
str.length * glyphWidth
,因为等宽字体中的每个字形都具有相同的前进宽度。上面的解决方案适用于非等宽字体,而这些字体大多带有字距对,因此计算不会很精确。 - Jürg Lehni这对我有效...
// 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;
}
getComputedStyle(lDiv).width
。 - Octo PoulosjQuery:
(function($) {
$.textMetrics = function(el) {
var h = 0, w = 0;
var div = document.createElement('div');
document.body.appendChild(div);
$(div).css({
position: 'absolute',
left: -1000,
top: -1000,
display: 'none'
});
$(div).html($(el).html());
var styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing'];
$(styles).each(function() {
var s = this.toString();
$(div).css(s, $(el).css(s));
});
h = $(div).outerHeight();
w = $(div).outerWidth();
$(div).remove();
var ret = {
height: h,
width: w
};
return ret;
}
})(jQuery);
ExtJS JavaScript库有一个很棒的类叫做Ext.util.TextMetrics,它"为文本块提供精确的像素测量,以便您可以确定给定文本块的高度和宽度(以像素为单位)"。 您可以直接使用它或查看其源代码来了解如何完成此操作。
http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html
我为此编写了一个小工具。也许对某些人有用。它可以在没有jQuery的情况下运行。
https://github.com/schickling/calculate-size
使用方法:
var size = calculateSize("Hello world!", {
font: 'Arial',
fontSize: '12px'
});
console.log(size.width); // 65
console.log(size.height); // 14
Fiddle:http://jsfiddle.net/PEvL8/
<span id="text">Text</span>
<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>
只要标签没有其他样式应用于它,这个方法就可以工作。
offsetWidth将包括任何边框、水平填充、垂直滚动条宽度等的宽度。
您可以使用画布,这样您就不必处理太多的CSS属性:
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "20pt Arial"; // This can be set programmaticly from the element's font-style if desired
var textWidth = ctx.measureText($("#myElement").text()).width;