web-dev-qa-db-ja.com

JavaScriptでテキスト幅を計算する

JavaScriptを使用して文字列の幅を計算したいのですが。固定幅フォントを使用せずにこれを実行できますか。

それが組み込まれていない場合、私の唯一のアイデアは各文字の幅のテーブルを作成することですが、これは特に Unicode と異なる型をサポートすることはかなり無理ですサイズ(そしてそれに関するすべてのブラウザ)。

418
Jacob

以下のスタイルの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>
326
CMPalmer

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メソッドを Bob MonteverdeのDOMベースのメソッド のバリエーションと比較するため、結果の正確さを分析および比較できます。

この方法には、次のようないくつかの利点があります。

注:DOMにテキストを追加するときは、 パディング、マージン、ボーダー も考慮に入れることを忘れないでください。

注2:ブラウザによっては、この方法でサブピクセル精度(結果は浮動小数点数)が得られますが、そうでないもの(結果はintのみ)があります。矛盾を避けるために、結果に対してMath.floor(またはMath.ceil)を実行することをお勧めします。 DOMベースの方法はサブピクセル精度ではありませんので、この方法は他の方法よりもさらに高い精度を持ちます。

this jsperf によると(コメントの貢献者のおかげで)、CanvasメソッドDOMベースのメソッドはほぼ同じ速さです。DOMベースのメソッドにキャッシュが追加されていて、Firefoxを使用していない場合Firefoxでは、何らかの理由で、このCanvasメソッドDOMベースのメソッドよりはるかに高速です(2014年9月現在)。

323
Domi

これは私が例なしで一緒にホイップしたものです。私たち全員が同じページにいるようです。

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を追加しました。

105
Bob Monteverde

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);
30
Deepak Nadar

これは私のために働きます...

// 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;
}
23
Pete

ExtJS javascriptライブラリ はExt.util.TextMetricsという素晴らしいクラスを持っています。幅が広く、ピクセル単位で、与えられたテキストブロックは ""になります。これを直接使用するか、そのソースを表示してコード化する方法を確認できます。

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

19
big lep

静的な文字幅マップを作成するだけのあなたの「唯一のアイデア」が好きです。それは実際に私の目的のためにうまく機能します。場合によっては、パフォーマンス上の理由から、またはDOMに簡単にアクセスできないために、ただ1つのフォントに合わせて調整された迅速でハッカーの多いスタンドアロンの電卓が必要な場合があります。それで、これは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のみをサポートします(それ以外の場合は平均文字幅を想定しています)。幸いなことに、widthは基本的にフォントサイズに比例して増減するので、どのフォントサイズでもうまく機能します。カーニングや合字など何も意識していません。

"調整"するために、私はsvg上のcharCode 126(強力なチルダ)までのすべての文字をレンダリングし、バウンディングボックスを得て、それをこの配列に保存しました。 より多くのコードと説明とデモはこちら

10
Toph

そのための小さなツールを書きました。おそらくそれは誰にとっても役に立つでしょう。 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/

10
schickling

キャンバスを使用すると、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;
6
rysama
<span id="text">Text</span>

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

<span>タグに他のスタイルが適用されていない限り、これは機能します。 offsetWidthには、境界線の幅、水平方向の余白、垂直方向のスクロールバーの幅などが含まれます。

4
Bryan Friedman

以下のコードスニップは、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)
        }
    }
});
2
Techek

このコードを試してください:

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;
}
1
Jason Bracey

他の誰かがここで文字列の幅を測定する方法の両方を入れる方法を探しています。特定の幅、これは二分探索を用いた@ 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;
        }
    }
}
1
M Katz

Deepak Nadarの答え をもとに、関数のパラメータをテキストとフォントのスタイルを受け入れるように変更しました。要素を参照する必要はありません。また、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>
1
Mr. Polywhirl

より良いのは、要素を表示する直前にテキストが収まるかどうかを検出することです。そのため、要素を画面に表示する必要のないこの機能を使用できます。

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

テキストの幅と高さはclientWidthclientHeightで得られます。

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

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

style positionプロパティがabsoluteに設定されていることを確認してください。

element.style.position = "absolute";

divの内側にある必要はなく、pまたはspanの内側に置くことができます。

1
Gjaa

これはDepakのエントリと似ているが、 impressivewebsページの記事で公開されているLouis Lazarisの作品に基づいている

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

0
Mauricio

実例をいじる: 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");
0
Jason Williams

Element.getClientRects()メソッドは、クライアント内の各CSSボーダーボックスの境界矩形を示すDOMRectオブジェクトのコレクションを返します。戻り値はDOMRectオブジェクトのコレクションです。要素に関連付けられたCSSボーダーボックスごとに1つです。各DOMRectオブジェクトには、境界線ボックスを記述する読み取り専用のlefttopright、およびbottomプロパティがピクセル単位で含まれ、ビューポートの左上を基準にした左上が表示されます。

Element.getClientRects() by Mozilla ContributorsCC-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>
0
transistor09

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

私は小さな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属性も考慮に入れることを可能にします!

0
Roman86