我想用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 /sf/ask/17360801/#21015393 */ function getTextWidth(text, font) { // re-use canvas object for better performance var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas")); var context = canvas.getContext("2d"); context.font = font; var metrics = context.measureText(text); return metrics.width; } console.log(getTextWidth("hello there!", "bold 12pt arial")); // close to 86
这个小提琴将这种Canvas方法与Bob Monteverde基于DOM的方法的变体进行比较,因此您可以分析和比较结果的准确性.
这种方法有几个优点,包括:
比其他(基于DOM)方法更简洁,更安全,因为它不会改变全局状态,例如DOM.
通过修改更多画布文本属性(例如textAlign
和)可以进一步自定义textBaseline
.
注意:当您将文本添加到DOM时,请记住还要考虑填充,边距和边框.
注2:在某些浏览器中,此方法产生子像素精度(结果是浮点数),而在其他浏览器上则不然(结果只是一个int).您可能希望对结果运行Math.floor
(或Math.ceil
),以避免不一致.由于基于DOM的方法从不是亚像素精确的,因此这种方法比其他方法具有更高的精度.
根据这个jsperf(感谢评论中的贡献者),如果将缓存添加到基于DOM的方法而您没有使用Firefox ,那么Canvas方法和基于DOM的方法大致相同.在Firefox中,出于某种原因,这种Canvas方法比基于DOM的方法快得多(截至2014年9月).
使用以下样式创建样式的DIV.在JavaScript中,设置您要测量的字体大小和属性,将字符串放在DIV中,然后读取DIV的当前宽度和高度.它将拉伸以适合内容,并且大小将在字符串渲染大小的几个像素内.
var 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 */
}
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
这是我在没有例子的情况下一起鞭打的人.看起来我们都在同一页面上.
String.prototype.width = function(font) { var f = font || '12px arial', o = $('') .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
了宽度大于窗口宽度的字符串可以计算.
jQuery的:
(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);
这对我有用......
// 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.innerHTML = pText; var lResult = { width: lDiv.clientWidth, height: lDiv.clientHeight }; document.body.removeChild(lDiv); lDiv = null; return lResult; }
该ExtJS的JavaScript库有一个名为Ext.util.TextMetrics说,"为文本块精确测量像素,让您可以准确确定的高和宽,以像素为单位,文本的给定块将是"一个伟大的阶级.您既可以直接使用它,也可以查看其源代码以了解如何完成此操作.
http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html
我喜欢你只做一个静态字符宽度图的"唯一想法"!它实际上适合我的目的.有时,出于性能原因或者您无法轻松访问DOM,您可能只需要一个快速hacky独立计算器校准到单个字体.所以这里有一个校准到Helvetica; 传递一个字符串和(可选)字体大小:
function measureText(str, fontSize = 10) { 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 return str .split('') .map(c => c.charCodeAt(0) < widths.length ? widths[c.charCodeAt(0)] : avg) .reduce((cur, acc) => acc + cur) * fontSize }
那个巨大的丑陋数组是由字符代码索引的ASCII字符宽度.所以这只支持ASCII(否则它假设平均字符宽度).幸运的是,宽度基本上与字体大小成线性比例,所以它适用于任何字体大小.它显然缺乏对字距或连字或其他任何东西的认识.
为了"校准",我只是将每个字符渲染到svg上的charCode 126(强大的波浪号)并获得边界框并将其保存到此数组中; 这里有更多代码,解释和演示.
我为此写了一个小工具.也许这对某人有用.它没有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
小提琴:http://jsfiddle.net/PEvL8/
您可以使用画布,这样您就不必处理如此多的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;
Text
只要标记没有应用其他样式,它就应该起作用。offsetWidth将包括任何边框的宽度,水平填充,垂直滚动条宽度等。