Я хотел бы использовать JavaScript для вычисления ширины строки. Возможно ли это без использования моноширинного шрифта?
Если он не встроен, моя единственная идея - создать таблицу ширины для каждого символа, но это довольно неразумно, особенно с поддержкой Юникод и разных размеров шрифтов (и всех браузеров в этом отношении).



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Создайте 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.info(height, width);#Test
{
position: absolute;
visibility: hidden;
height: auto;
width: auto;
white-space: nowrap; /* Thanks to Herb Caudill comment */
}<div id = "Test">
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>Единственное, что я бы добавил, это то, что это может давать неправильные размеры в зависимости от того, какие стили используются. Помните, что у вас могут быть такие стили, как p {letter-spacing: 0.1em; } что элемент DIV не будет отражать. Вы должны убедиться, что используемые стили подходят для того, где вы будете использовать текст.
То же, что и комментарий Джима - дважды проверьте, чтобы к контейнеру, в данном случае div, не применялись какие-либо другие стили, примененные к нему с помощью правил выбора css, о которых вы, возможно, не знали в то время. Снимите с контейнера все подходящие стили, прежде чем применять те, которые вам нужны, перед измерением.
Вы также должны ввести white-space: nowrap, если вы думаете, что текст будет превышать ширину браузера.
этот ответ не сработал для меня, он сначала дал мне неправильные значения, продолжал их увеличивать, и только после пары звонков у меня были правильные. Что исправлено, так это замена visibility:hidden на верхний / левый, установленный на -1000 пикселей.
+1 для абсолютного позиционирования, которое, кажется, упускается во многих сообщениях ... без него вы получаете пространство, занимаемое div из-за использования visibility:hidden вместо `display: none '(что не работает для этого )
@Bog все эти взломы - вот почему я предлагаю другой, менее хакерский, подход внизу. Взгляните на это здесь.
Просто любопытно, для чего нужен +1 по каждому измерению?
Это решение вызывает синхронный макет, который может быть довольно медленным для многих элементов на странице.
Блестящая идея - отстой, нам нужно взломать, чтобы получить эту информацию
У меня это не работает. test.clientWidth и test.clientHeight всегда возвращают 0.
изменение значения fontSize, отличного от 12, не влияет на результат в моем испытании с ie11. я попробовал именно так, как в ответе.
<span id = "text">Text</span>
<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>
Это должно работать, пока к тегу <span> не применяются другие стили. offsetWidth будет включать ширину любых границ, горизонтальное заполнение, ширину вертикальной полосы прокрутки и т. д.
Это более или менее то, что делает верхние решения, но поскольку ваш текст может быть разделен на несколько строк, они добавляют некоторые стили CSS к тексту, чтобы получить реальную полную ширину текста.
Библиотека javascript ExtJS имеет отличный класс под названием Ext.util.TextMetrics, который «обеспечивает точные пиксельные измерения для блоков текста, так что вы можете точно определить, насколько высоким и широким в пикселях будет данный блок текста». Вы можете использовать его напрямую или просмотреть его исходный код в коде, чтобы увидеть, как это делается.
http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html
У ExtJS лишняя лицензия. Либо вы платите текущим сопровождающим, компании Sencha за его использование, либо вы должны открыть исходный код всего связанного кода в своем приложении. Это шоу-пробка для большинства компаний. jQuery, с другой стороны, использует разрешающую лицензию MIT.
Разве javascript автоматически не соответствует требованиям открытого исходного кода? Вы предоставляете источник любому, кто просматривает страницу.
Есть разница между возможностью просмотра исходного кода и открытым исходным кодом, которая определяется лицензированием.
Спасибо тем из нас, кто все еще использует ExtJS :-)
вы должны были позволить ExtJS покоиться с миром
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);
Приведенные ниже фрагменты кода «вычисляют» ширину тега span, добавляют к нему «...», если он слишком длинный, и сокращают длину текста, пока он не уместится в своем родителе (или пока он не попробует больше, чем тысячи раз)
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)
}
}
});
Попробуйте двоичный поиск вместо того, чтобы зацикливать по одному символу за раз: см. Мой комментарий к ответу Алекса на stackoverflow.com/questions/536814/…
@StanleyH: Хорошая идея - я выполню ваше предложение как можно скорее.
Это работает для меня ...
// 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;
}
Привет, ваш ответ действительно полезен, однако используйте .cssText вместо .style для поддержки IE 8 и ниже.
Это отличный ответ, но когда я создаю большой кусок текста, он становится неточным на несколько пикселей. Это потому, что ширина не является целым числом?
Не используйте это решение в его текущем состоянии. Используйте textContent вместо innerHTML для устранения уязвимости XSS.
Вот один, который я собрал без примера. Похоже, мы все находимся на одной странице.
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, чтобы можно было вычислить строки, ширина которых больше ширины окна.
Спасибо, JordanC. Я бы добавил, что если вы вызываете это много раз на одной и той же странице, и производительность является проблемой, вы можете сохранить DIV и просто изменить содержимое и проверить ширину. Я просто сделал это так, чтобы, как только все было сказано и сделано, DOM будет таким же, как когда вы начали
В моей версии я использовал объект вместо аргумента шрифта, поэтому вы можете передать аргументы css в div для выделения жирным шрифтом, курсивом и т. д.
Я бы не стал добавлять этот метод в String, поскольку он уменьшает разделение проблем вашей программы (отдельный код ядра и код пользовательского интерфейса). Представьте, что вы хотите перенести свой основной код на платформу с совершенно другой структурой пользовательского интерфейса ...
Это плохой дизайн, он не только связывает вашу модель с вашим представлением, но и напрямую связывает его с jQuery. Вдобавок это ад оплавления, это точно не будет хорошо масштабироваться.
Если вам нужно значение с плавающей запятой, вы можете использовать o[0].getBoundingClientRect().width, как предлагается здесь: stackoverflow.com/a/16072668/936397
Вы забыли упомянуть, что для этого требуется jQuery.
отличные баллы от @James, но здесь приземлились более 100 человек, которые не особо заботятся об архитектуре
@virus хорошо сказал, что 100+ человек, вероятно, тоже не заботятся о производительности ... Тем не менее, это не делает то, что я сказал, менее достоверным или правдивым.
Вы можете использовать холст, чтобы вам не приходилось так много работать со свойствами 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;
Разве это не намного тяжелее (с получением 2d-контекста и т. д.), Чем создание элемента DOM и указание для него свойств css?
Это чистый подход, если вы уже для чего-то используете холст. Но ОЧЕНЬ МЕДЛЕННО. Один только вызов measureText занимает около 8-10 мс (при использовании Chrome).
Попробуйте этот код:
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;
}
Ширину и высоту текста можно получить с помощью clientWidth и clientHeight.
var element = document.getElementById ("mytext");
var width = element.clientWidth;
var height = element.clientHeight;
убедитесь, что свойство позиции стиля установлено на абсолютное
element.style.position = "absolute";
необязательно находиться внутри div, может быть внутри p или span
Лучше всего определить, подходит ли текст, прямо перед отображением элемента. Таким образом, вы можете использовать эту функцию, которая не требует, чтобы элемент был на экране.
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) {
...
}
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'));
В 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 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.info(getTextWidth("hello there!", "bold 12pt arial")); // close to 86
Эта рабочий пример сравнивает этот метод Canvas с вариантом Метод Боба Монтеверде на основе DOM, чтобы вы могли анализировать и сравнивать точность результатов.
У этого подхода есть несколько преимуществ, в том числе:
textAlign и textBaseline.ПРИМЕЧАНИЕ. Когда вы добавляете текст в DOM, не забудьте также принять во внимание отступы, поля и граница.
ПРИМЕЧАНИЕ 2. В некоторых браузерах этот метод дает субпиксельную точность (результат - число с плавающей запятой), в других - нет (результат - только int). Возможно, вы захотите запустить Math.floor (или Math.ceil) для получения результата, чтобы избежать несоответствий. Поскольку метод на основе DOM никогда не бывает субпиксельным, этот метод имеет даже более высокую точность, чем другие методы, представленные здесь.
Согласно этот jsperf (спасибо участникам в комментариях), Метод холста и Метод на основе DOM примерно одинаково быстры, если к Метод на основе DOM добавлено кеширование и вы не используете Firefox. В Firefox по какой-то причине этот Метод холста намного быстрее, чем Метод на основе DOM (по состоянию на сентябрь 2014 г.).
Это отличный вариант, я о нем не знала. Вы когда-нибудь сравнивали производительность этого метода с производительностью измерения в DOM?
@SimpleAsCouldBe Я только что изучил это и нашел этот тест ширины текста на jsperf.com. Он говорит мне, что метод Canvas в 6 раз быстрее, но он не кэширует DOM в другом методе, поэтому он предвзят.
Я добавил кеширование в этот тест jsperf. Теперь два метода почти равны: jsperf.com/measure-text-width/4
Кстати, изменение шрифта на холсте приводит к перерасчету стилей, что может быть довольно медленным на странице с большим количеством элементов HTML.
@ Мартин А? При чем здесь «много элементов HTML»? Объект холста в этом примере даже не прикреплен к DOM. И даже помимо этого, изменение шрифта в контексте рисования холста даже не влияет на холст, пока вы не используете strokeText() или fillText(). Возможно, вы хотели прокомментировать другой ответ?
Хорошее решение. Я обернул пару других методов вокруг ответа Доми, чтобы я мог - получить (потенциально) усеченную строку с многоточием (...) в конце, если она не помещается в заданное пространство (столько, сколько строка по возможности будет использоваться) - Передайте элемент JQuery, который должен содержать (возможно, усеченную) строку, и динамически определять атрибуты шрифта, чтобы их не нужно было жестко запрограммировать, что позволяет изменять атрибуты шрифта CSS без нарушения расположение. JSFiddle Здесь: jsfiddle.net/brebey/1q94gLsu/6/embed
Размер шрифта на самом деле не является его высотой. Пример: высота Helvetica 16px всего 18 пикселей ...
Я забыл, где я нашел информацию об этом, но, согласно этому источнику, размер шрифта в пунктах должен быть максимальной высотой любого символа (или, по крайней мере, любого символа ASCII?). Возможно, ошиблись ... Я сейчас уберу этот намек. Спасибо!
??? не работает «Uncaught ReferenceError: getTextWidth не определен» в строке var canvas = getTextWidth.canvas || (GetT ...
@ user1709076 Используете ли вы его с Node или какой-либо другой безголовой средой Javascript, которая на самом деле не определяет DOM? Это не сработает, если вы не установите специальную среду, например PhantomJS. Однако он должен работать во всех основных браузерах. См. здесь для таблицы, показывающей вам все поддерживаемые браузеры и версии.
Есть ли способ вернуть этот ответ в баллах? или другие единицы?
@Trenton Насколько я понимаю, коэффициент преобразования pixel в point зависит от самого шрифта (подумайте: если бы это было так легко преобразовать, зачем нам было бы измерять его для начала? Разные символы уже имеют разную высоту точки!) а также носитель, который вы используете (например, экран вашего компьютера), его разрешение и даже реализацию конвейера рендеринга в браузере. У конвертера Этот есть примечание (буквально справа), которое вы можете прочитать
Этот не учитывает все возможные стили CSS, которые могут применяться к строке после ее отображения на странице.
@vsync Вы правы. Он не может учитывать text-transform, letter-spacing и др. (Пока), но учитывает наиболее часто встречающиеся требования.
Хорошо, потому что пользователь этого не видит!
На случай, если кто-то еще пришел сюда и искал способ измерения ширины строки и способ узнать, какой самый большой размер шрифта подходит для определенной ширины, я добавил ответ (stackoverflow.com/a/50813259/384670), основанный на этом решении. с бинарным поиском.
Это будет работать в Chrome, но даст неправильный результат в Firefox.
Я написал для этого небольшой инструмент. Возможно, это кому-нибудь пригодится. Работает без jQuery.
https://github.com/schickling/calculate-size
Использование:
var size = calculateSize("Hello world!", {
font: 'Arial',
fontSize: '12px'
});
console.info(size.width); // 65
console.info(size.height); // 14
Рабочий пример: http://jsfiddle.net/PEvL8/
Я предполагаю, что это прети похоже на запись Depak, но основана на работе Луи Лазариса, опубликованной в статье в впечатляющая веб-страница
(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);
Событие соответствия используется для выполнения вызова функции сразу после того, как функция привязана к элементу управления.
например: $ ('input'). autofit (). trigger ("соответствовать");
Без 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);
когда вы устанавливаете число, не работает, потому что в пробеле нет необходимости, если вы его удалите, он будет работать нормально: размер шрифта + «px arial» -> fontSize + «px arial», вот и все.
Сценарий рабочего примера: 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");
Основываясь на Ответ Дипака Надара, я изменил параметр functions, чтобы он принимал стили текста и шрифтов. Ссылка на элемент не требуется. Кроме того, 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));<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>Мне нравится ваша "единственная идея" просто сделать карту ширины статического символа! Это действительно хорошо работает для моих целей. Иногда по соображениям производительности или из-за того, что у вас нет легкого доступа к DOM, вам может потребоваться быстрый автономный калькулятор, откалиброванный для одного шрифта. Итак, вот один, откалиброванный для 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 (в противном случае предполагается средняя ширина символа). К счастью, ширина в основном линейно масштабируется с размером шрифта, поэтому она хорошо работает с любым размером шрифта. Ему явно не хватает понимания кернинга, лигатур или чего-то еще.
Для «калибровки» я просто визуализировал каждый символ до charCode 126 (могущественная тильда) в svg, получил ограничивающую рамку и сохранил ее в этом массиве; больше кода, объяснения и демонстрации здесь.
это умное решение, хорошее :) Я всегда использую один и тот же шрифт / размер, так что он мне подходит. Я обнаружил, что производительность решений DOM / Canvas представляет собой настоящую проблему, это действительно чисто, ура!
устраняет необходимость в холсте +1
Вы можете избавиться от * fontSize и просто использовать их
Какой замечательный ответ!
хорошее решение, потому что это также работает на стороне сервера.
The
Element.getClientRects()method returns a collection ofDOMRectobjects that indicate the bounding rectangles for each CSS border box in a client. The returned value is a collection ofDOMRectobjects, one for each CSS border box associated with the element. EachDOMRectobject contains read-onlyleft,top,rightandbottomproperties describing the border box, in pixels, with the top-left relative to the top-left of the viewport.
Element.getClientRects() by Mozilla Contributors is licensed under 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>В случае, если кто-то еще искал способ измерения ширины строки и, чтобы узнать, какой самый большой размер шрифта подходит для определенной ширины, вот функция, которая основывается на @ Решение Доми с двоичным поиском:
/**
* 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 {Number} width - The width in pixels the string must fit in
* @param {Number} minFontPx - The smallest acceptable font size in pixels
* @param {Number} 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;
}
}
}
Это работает потрясающе (в сочетании с кодом из ответа Доми)
Перепиши свой ответ с нуля (спасибо за минус). Теперь функция принимает правила текста и css (и больше не использует jQuery). Так что он также будет уважать прокладки. Результирующие значения округляются (вы можете увидеть Math.round там, удалите, если хотите более точные значения)
function getSpan(){
const span = document.createElement('span')
span.style.position = 'fixed';
span.style.visibility = 'hidden';
document.body.appendChild(span);
return span;
}
function textWidth(str, css) {
const span = getSpan();
Object.assign(span.style, css || {});
span.innerText = str;
const w = Math.round(span.getBoundingClientRect().width);
span.remove();
return w;
}
const testStyles = [
{fontSize: '10px'},
{fontSize: '12px'},
{fontSize: '60px'},
{fontSize: '120px'},
{fontSize: '120px', padding: '10px'},
{fontSize: '120px', fontFamily: 'arial'},
{fontSize: '120px', fontFamily: 'tahoma'},
{fontSize: '120px', fontFamily: 'tahoma', padding: '5px'},
];
const ul = document.getElementById('output');
testStyles.forEach(style => {
const li = document.createElement('li');
li.innerText = `${JSON.stringify(style)} > ${textWidth('abc', style)}`;
ul.appendChild(li);
});<ul id = "output"></ul>Вы также можете сделать это с помощью 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;
}
Я использую пакет текстовые метрики. Работает очень хорошо, я пробовал этот решение, но по некоторым причинам он неправильно считает.
textMetrics.init(document.querySelector('h1'), { fontSize: '20px' });
textMetrics.init({
fontSize: '14px',
lineHeight: '20px',
fontFamily: 'Helvetica, Arial, sans-serif',
fontWeight: 400,
width: 100,
});
Помните, что если вы используете внешние шрифты, вам придется использовать описанные ниже методы после их загрузки. Вы можете не осознавать этого, если они кешированы или у вас установлены локальные версии.