我想用JavaScript来计算字符串的宽度。这可能不需要使用等宽字体吗?
如果它不是内置的,我唯一的想法是为每个角色创建一个宽度表,但这是非常不合理的,特别是支持Unicode和不同的类型大小(以及所有浏览器)。< / p>
答案 0 :(得分:325)
使用以下样式创建样式的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 */
}
<div id="Test">
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>
答案 1 :(得分:321)
在 HTML 5 中,您只需使用Canvas.measureText method(进一步说明here)。
/**
* 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
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
This fiddle将此Canvas方法与Bob Monteverde's DOM-based method的变体进行比较,因此您可以分析并比较结果的准确性。
这种方法有几个优点,包括:
textAlign
和textBaseline
。注意:将文字添加到DOM时,请记住同时考虑padding, margin and border。
注意2:在某些浏览器中,此方法产生子像素精度(结果是浮点数),而在其他浏览器上则没有(结果只是一个int)。您可能希望对结果运行Math.floor
(或Math.ceil
),以避免出现不一致。由于基于DOM的方法从不是亚像素精确的,因此这种方法比其他方法具有更高的精度。
根据this jsperf(感谢评论中的贡献者), Canvas方法和基于DOM的方法大致相同,如果缓存是添加到基于DOM的方法并且您没有使用Firefox。在Firefox中,出于某种原因,这个 Canvas方法比基于DOM的方法快得多(截至2014年9月)。
答案 2 :(得分:106)
这是我在没有例子的情况下一起鞭打的人。看起来我们都在同一页上。
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
,因此可以计算宽度大于窗口宽度的字符串。
答案 3 :(得分:31)
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);
答案 4 :(得分:23)
这对我有用......
// 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;
}
答案 5 :(得分:19)
ExtJS javascript library有一个名为Ext.util.TextMetrics的优秀类,它“为文本块提供精确的像素测量,以便您可以精确确定给定文本块的高度和宽度(以像素为单位) ”。您既可以直接使用它,也可以查看其源代码以了解如何完成此操作。
http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html
答案 6 :(得分:10)
我为此写了一个小工具。也许这对某人有用。它可以没有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
答案 7 :(得分:9)
我喜欢你的#34;唯一的想法&#34;只是做一个静态字符宽度图!它实际上适合我的目的。有时,出于性能原因或者您无法轻松访问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(否则它假设平均字符宽度)。幸运的是,宽度基本上与字体大小成线性比例,所以它适用于任何字体大小。它显然缺乏任何关于字距调整或连字或任何其他的意识。
To&#34;校准&#34;我只是在svg上将每个字符渲染到charCode 126(强大的波浪号)并获得边界框并将其保存到此数组中; more code and explanation and demo here
答案 8 :(得分:6)
您可以使用画布,这样您就不必处理如此多的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;
答案 9 :(得分:4)
<span id="text">Text</span>
<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>
这应该与&lt; span&gt;一起使用。 tag没有应用其他样式。 offsetWidth将包括任何边框的宽度,水平填充,垂直滚动条宽度等。
答案 10 :(得分:2)
下面的代码剪切,“计算”span-tag的宽度,如果它太长则会向其添加“...”并减少文本长度,直到它适合其父级(或直到它具有尝试了一千多次)
CSS
div.places {
width : 100px;
}
div.places span {
white-space:nowrap;
overflow:hidden;
}
HTML
<div class="places">
<span>This is my house</span>
</div>
<div class="places">
<span>And my house are your house</span>
</div>
<div class="places">
<span>This placename is most certainly too wide to fit</span>
</div>
JavaScript(使用jQuery)
// loops elements classed "places" and checks if their child "span" is too long to fit
$(".places").each(function (index, item) {
var obj = $(item).find("span");
if (obj.length) {
var placename = $(obj).text();
if ($(obj).width() > $(item).width() && placename.trim().length > 0) {
var limit = 0;
do {
limit++;
placename = placename.substring(0, placename.length - 1);
$(obj).text(placename + "...");
} while ($(obj).width() > $(item).width() && limit < 1000)
}
}
});
答案 11 :(得分:1)
更好的方法是在显示元素之前检测文本是否适合。所以你可以使用这个不需要元素在屏幕上的功能。
function textWidth(text, fontProp) {
var tag = document.createElement("div");
tag.style.position = "absolute";
tag.style.left = "-999em";
tag.style.whiteSpace = "nowrap";
tag.style.font = fontProp;
tag.innerHTML = text;
document.body.appendChild(tag);
var result = tag.clientWidth;
document.body.removeChild(tag);
return result;
}
用法:
if ( textWidth("Text", "bold 13px Verdana") > elementWidth) {
...
}
答案 12 :(得分:1)
可以使用clientWidth
和clientHeight
var element = document.getElementById ("mytext");
var width = element.clientWidth;
var height = element.clientHeight;
确保样式位置属性设置为绝对
element.style.position = "absolute";
不需要位于div
内,可以位于p
或span
答案 13 :(得分:1)
试试这段代码:
function GetTextRectToPixels(obj)
{
var tmpRect = obj.getBoundingClientRect();
obj.style.width = "auto";
obj.style.height = "auto";
var Ret = obj.getBoundingClientRect();
obj.style.width = (tmpRect.right - tmpRect.left).toString() + "px";
obj.style.height = (tmpRect.bottom - tmpRect.top).toString() + "px";
return Ret;
}
答案 14 :(得分:1)
建立Deepak Nadar's answer,我更改了函数参数&#39; s以接受文本和字体样式。您不需要引用元素。此外,fontOptions
有默认值,因此您无需提供所有这些内容。
(function($) {
$.format = function(format) {
return (function(format, args) {
return format.replace(/{(\d+)}/g, function(val, pos) {
return typeof args[pos] !== 'undefined' ? args[pos] : val;
});
}(format, [].slice.call(arguments, 1)));
};
$.measureText = function(html, fontOptions) {
fontOptions = $.extend({
fontSize: '1em',
fontStyle: 'normal',
fontWeight: 'normal',
fontFamily: 'arial'
}, fontOptions);
var $el = $('<div>', {
html: html,
css: {
position: 'absolute',
left: -1000,
top: -1000,
display: 'none'
}
}).appendTo('body');
$(fontOptions).each(function(index, option) {
$el.css(option, fontOptions[option]);
});
var h = $el.outerHeight(), w = $el.outerWidth();
$el.remove();
return { height: h, width: w };
};
}(jQuery));
var dimensions = $.measureText("Hello World!", { fontWeight: 'bold', fontFamily: 'arial' });
// Font Dimensions: 94px x 18px
$('body').append('<p>').text($.format('Font Dimensions: {0}px x {1}px', dimensions.width, dimensions.height));
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
答案 15 :(得分:1)
如果有其他人在这里寻找一种方法来测量字符串的宽度和,这是一种了解什么是适合特定宽度的最大字体大小的方法,这是一个基于@ Domi的二进制搜索解决方案的功能:
/**
* Find the largest font size (in pixels) that allows the string to fit in the given width.
*
* @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 ?px verdana") -- note the use of ? in place of the font size.
* @param {width} the width in pixels the string must fit in
* @param {minFontPx} the smallest acceptable font size in pixels
* @param {maxFontPx} the largest acceptable font size in pixels
**/
function GetTextSizeForWidth( text, font, width, minFontPx, maxFontPx )
{
for ( ; ; )
{
var s = font.replace( "?", maxFontPx );
var w = GetTextWidth( text, s );
if ( w <= width )
{
return maxFontPx;
}
var g = ( minFontPx + maxFontPx ) / 2;
if ( Math.round( g ) == Math.round( minFontPx ) || Math.round( g ) == Math.round( maxFontPx ) )
{
return g;
}
s = font.replace( "?", g );
w = GetTextWidth( text, s );
if ( w >= width )
{
maxFontPx = g;
}
else
{
minFontPx = g;
}
}
}
答案 16 :(得分:1)
您还可以使用createRange做到这一点,它比文本克隆技术更准确:
function getNodeTextWidth(nodeWithText) {
var textNode = $(nodeWithText).contents().filter(function () {
return this.nodeType == Node.TEXT_NODE;
})[0];
var range = document.createRange();
range.selectNode(textNode);
return range.getBoundingClientRect().width;
}
答案 17 :(得分:0)
我猜这是类似于Depak条目的,但是基于Louis Lazaris在impressivewebs page
中的一篇文章中发表的作品。(function($){
$.fn.autofit = function() {
var hiddenDiv = $(document.createElement('div')),
content = null;
hiddenDiv.css('display','none');
$('body').append(hiddenDiv);
$(this).bind('fit keyup keydown blur update focus',function () {
content = $(this).val();
content = content.replace(/\n/g, '<br>');
hiddenDiv.html(content);
$(this).css('width', hiddenDiv.width());
});
return this;
};
})(jQuery);
fit事件用于在函数与控件相关联后立即执行函数调用。
例如:$('input')。autofit()。trigger(“fit”);
答案 18 :(得分:0)
没有jQuery:
String.prototype.width = function (fontSize) {
var el,
f = fontSize + " px arial" || '12px arial';
el = document.createElement('div');
el.style.position = 'absolute';
el.style.float = "left";
el.style.whiteSpace = 'nowrap';
el.style.visibility = 'hidden';
el.style.font = f;
el.innerHTML = this;
el = document.body.appendChild(el);
w = el.offsetWidth;
el.parentNode.removeChild(el);
return w;
}
// Usage
"MyString".width(12);
答案 19 :(得分:0)
工作示例的小提琴:http://jsfiddle.net/tdpLdqpo/1/
HTML:
<h1 id="test1">
How wide is this text?
</h1>
<div id="result1"></div>
<hr/>
<p id="test2">
How wide is this text?
</p>
<div id="result2"></div>
<hr/>
<p id="test3">
How wide is this text?<br/><br/>
f sdfj f sdlfj lfj lsdk jflsjd fljsd flj sflj sldfj lsdfjlsdjkf sfjoifoewj flsdjfl jofjlgjdlsfjsdofjisdojfsdmfnnfoisjfoi ojfo dsjfo jdsofjsodnfo sjfoj ifjjfoewj fofew jfos fojo foew jofj s f j
</p>
<div id="result3"></div>
JavaScript代码:
function getTextWidth(text, font) {
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;
};
$("#result1")
.text("answer: " +
getTextWidth(
$("#test1").text(),
$("#test1").css("font")) + " px");
$("#result2")
.text("answer: " +
getTextWidth(
$("#test2").text(),
$("#test2").css("font")) + " px");
$("#result3")
.text("answer: " +
getTextWidth(
$("#test3").text(),
$("#test3").css("font")) + " px");
答案 20 :(得分:0)
Element.getClientRects()下的
Element.getClientRects()
方法返回DOMRect
个对象的集合,这些对象指示客户端中每个CSS边框的边界矩形。返回的值是DOMRect
个对象的集合,每个对象与该元素关联一个CSS边框。每个DOMRect
对象都包含描述边框的只读left
,top
,right
和bottom
属性,以像素为单位,左上角相对于视口的左上角。
Mozilla Contributors已获得CC-BY-SA 2.5许可。
总结所有返回的矩形宽度会产生总文本宽度(以像素为单位)。
document.getElementById('in').addEventListener('input', function (event) {
var span = document.getElementById('text-render')
span.innerText = event.target.value
var rects = span.getClientRects()
var widthSum = 0
for (var i = 0; i < rects.length; i++) {
widthSum += rects[i].right - rects[i].left
}
document.getElementById('width-sum').value = widthSum
})
<p><textarea id='in'></textarea></p>
<p><span id='text-render'></span></p>
<p>Sum of all widths: <output id='width-sum'>0</output>px</p>
答案 21 :(得分:0)
我已经制作了一个很小的ES6模块(使用jQuery):
import $ from 'jquery';
const $span=$('<span>');
$span.css({
position: 'absolute',
display: 'none'
}).appendTo('body');
export default function(str, css){
$span[0].style = ''; // resetting the styles being previously set
$span.text(str).css(css || {});
return $span.innerWidth();
}
易于使用:
import stringWidth from './string_width';
const w = stringWidth('1-3', {fontSize: 12, padding: 5});
您可能会注意到的很酷的事情-它可以考虑任何CSS属性,甚至包括填充!
答案 22 :(得分:0)
我正在使用text-metrics软件包。效果非常好,我尝试过此solution,但出于某些原因,它认为它是错误的。
textMetrics.init(document.querySelector('h1'), { fontSize: '20px' });
textMetrics.init({
fontSize: '14px',
lineHeight: '20px',
fontFamily: 'Helvetica, Arial, sans-serif',
fontWeight: 400,
width: 100,
});
答案 23 :(得分:-1)
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'));