Вычислить ширину текста с помощью JavaScript

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

Если он не встроен, моя единственная идея - создать таблицу ширины для каждого символа, но это довольно необоснованно, особенно поддерживая Unicode и различные типы размеров (и все браузеры, если на то пошло).

Ответ 1

Создайте стиль 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>

Ответ 2

В 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.log(getTextWidth("hello there!", "bold 12pt arial"));  // close to 86

Эта скрипка сравнивает этот метод Canvas с вариацией метода на основе Боба Монтеверде на основе DOM, поэтому вы можете анализировать и сравнивать точность результатов.

Для этого подхода есть несколько преимуществ, в том числе:

ПРИМЕЧАНИЕ. Когда вы добавляете текст в DOM, не забудьте также учитывать отступы, поля и границы.

ПРИМЕЧАНИЕ 2. В некоторых браузерах этот метод дает субпиксельную точность (результат - число с плавающей запятой), а на других - нет (результат - только int). Вы можете запустить Math.floor (или Math.ceil) в результате, чтобы избежать несоответствий. Поскольку метод на основе DOM никогда не является субпиксельным, этот метод имеет еще более высокую точность, чем другие методы здесь.

Согласно этому jsperf (спасибо вкладчикам в комментариях), метод Canvas и метод на основе DOM примерно одинаково быстры, если к DOM-методу добавляется кеширование и вы не используете Firefox. В Firefox по какой-то причине этот метод Canvas намного быстрее, чем метод на основе DOM (по состоянию на сентябрь 2014 года).

Ответ 3

Здесь я сгребался без примера. Похоже, мы все на одной странице.

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 поэтому можно рассчитать строки шириной больше ширины окна.

Ответ 4

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);

Ответ 5

Это работает для меня...

// Handy JavaScript to meature 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;
}

Ответ 6

Библиотека javascript ExtJS имеет отличный класс Ext.util.TextMetrics, который "обеспечивает точные измерения пикселей для блоков текста, чтобы вы могли точно определить, насколько высоки и широки в пикселях данный блок текста". Вы можете использовать его напрямую или просмотреть его источник для кода, чтобы узнать, как это делается.

http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html

Ответ 7

Я написал для этого небольшой инструмент. Возможно, это полезно кому-то. Он работает без 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/

Ответ 8

Вы можете использовать холст, так что вам не нужно иметь дело с css-свойствами:

var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "20pt Arial";  // This can be set programmaticly from the element font-style if desired
var textWidth = ctx.measureText($("#myElement").text()).width;

Ответ 9

<span id="text">Text</span>

<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>

Это должно работать до тех пор, пока <span> tag не имеет других примененных к нему стилей. offsetWidth будет включать ширину любых границ, горизонтальное заполнение, ширину полосы прокрутки по вертикали и т.д.

Ответ 10

Мне нравится ваша "единственная идея" просто сделать статическую карту ширины символов! Это действительно хорошо работает для моих целей. Иногда, по соображениям производительности или из-за того, что у вас нет простого доступа к 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 и получил ограничительную рамку и сохранил ее в этом массиве; больше кода и объяснений и демо здесь.

Ответ 11

Ниже перечислены фрагменты кода, "подсчитайте" ширину тега 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)
        }
    }
});

Ответ 12

Попробуйте этот код:

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;
}

Ответ 13

Ширина и высота текста можно получить с помощью clientWidth и clientHeight

var element = document.getElementById ("mytext");

var width = element.clientWidth;
var height = element.clientHeight;

убедитесь, что свойство позиции стиля установлено в абсолютное значение

element.style.position = "absolute";

не требуется находиться внутри div, может находиться внутри p или span

Ответ 14

Лучше всего определить, подходит ли текст прямо перед отображением элемента. Таким образом, вы можете использовать эту функцию, которая не требует, чтобы элемент находился на экране.

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) {
    ...
}

Ответ 15

Сценарий рабочего примера: 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");

Ответ 16

Создание Ответ Дипака Надара, я изменил параметр функций, чтобы принять стили текста и шрифта. Вам не нужно ссылаться на элемент. Кроме того, 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>

Ответ 17

Я предполагаю, что это prety, похожее на запись 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);

Событие fit используется для выполнения вызова функции по ошибке после того, как функция была связана с элементом управления.

например: $('input'). autofit(). trigger ( "fit" );

Ответ 18

Без 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

Метод Element.getClientRects() возвращает коллекцию объектов DOMRect которые указывают ограничивающие прямоугольники для каждого поля рамки CSS в клиенте. Возвращаемое значение представляет собой набор объектов DOMRect, по одному для каждого поля рамки CSS, связанного с элементом. Каждый объект DOMRect содержит свойства left, top, right и bottom только для чтения, описывающие рамку в пикселях, слева вверху относительно left top DOMRect окна просмотра.

Element.getClientRects() от Mozilla. Авторы лицензированы в 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>

Ответ 20

В случае, если кто-то еще сюда посмотрел, как способ измерения ширины строки, так и способ узнать, какой самый большой размер шрифта будет вписываться в определенную ширину, вот функция, которая строится на решении @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;
        }
    }
}

Ответ 21

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'));