web-dev-qa-db-fra.com

Calculer la largeur du texte avec JavaScript

J'aimerais utiliser JavaScript pour calculer la largeur d'une chaîne. Est-ce possible sans avoir à utiliser un caractère monospace?

Si ce n'est pas intégré, mon unique idée est de créer un tableau de largeur pour chaque caractère, mais cela est plutôt déraisonnable, surtout si vous utilisez Unicode et différentes tailles de caractères (et tous les navigateurs).

395
Jacob

Créez une DIV avec les styles suivants. Dans votre JavaScript, définissez la taille de la police et les attributs que vous essayez de mesurer, placez votre chaîne dans la DIV, puis lisez la largeur et la hauteur actuelles de la DIV. Il sera étiré pour s'adapter au contenu et la taille sera à quelques pixels de la taille de la chaîne rendue.

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>

316
CMPalmer

Dans HTML 5, vous pouvez simplement utiliser la méthode Canvas.measureText (explication supplémentaire ici ).

Essayez ce violon :

/**
 * 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

Ce violon compare cette méthode Canvas à une variante de de la méthode DOM de Bob Monteverde , afin que vous puissiez analyser et comparer la précision des résultats.

Cette approche présente plusieurs avantages, notamment:

REMARQUE: lorsque vous ajoutez le texte à votre DOM, n'oubliez pas de prendre également en compte le padding, margin et border .

REMARQUE 2: sur certains navigateurs, cette méthode permet d'obtenir une précision inférieure au pixel (le résultat est un nombre à virgule flottante), sur d'autres pas (le résultat est uniquement un entier). Vous voudrez peut-être exécuter Math.floor (ou Math.ceil) sur le résultat pour éviter les incohérences. Comme la méthode basée sur le DOM n'est jamais précise au sous-pixel, cette méthode a une précision encore plus élevée que les autres méthodes présentées ici.

Selon this jsperf (grâce aux contributeurs dans les commentaires), la méthode Canvas et la méthode DOM sont à peu près aussi rapides, si la mise en cache est ajoutée à la Méthode basée sur DOM et vous n'utilisez pas Firefox. Dans Firefox, pour une raison quelconque, cette méthode Canvas est beaucoup plus rapide que la méthode DOM (à compter de septembre 2014).

302
Domi

En voici un que j'ai fouetté ensemble sans exemple. On dirait que nous sommes tous sur la même page.

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

Son utilisation est simple: "a string".width()

** Ajout de white-space: nowrap pour que les chaînes avec une largeur supérieure à la largeur de la fenêtre puissent être calculées.

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

Cela fonctionne pour moi ...

// 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

La bibliothèque javascript ExtJS a une classe qui s'appelle Ext.util.TextMetrics qui "fournit des mesures de pixels précises pour les blocs de texte afin que vous puissiez déterminer exactement la hauteur et la largeur, en pixels, d'un bloc de texte donné" . Vous pouvez soit l'utiliser directement, soit afficher son code source pour voir comment procéder.

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

19
big lep

J'ai écrit un petit outil pour ça. C'est peut-être utile à quelqu'un. Cela fonctionne sans jQuery.

https://github.com/schickling/calculate-size

Usage:

var size = calculateSize("Hello world!", {
   font: 'Arial',
   fontSize: '12px'
});

console.log(size.width); // 65
console.log(size.height); // 14

Fiddle: http://jsfiddle.net/PEvL8/

10
schickling

J'aime votre "seule idée" de simplement faire une carte de largeur de caractère statique! Cela fonctionne bien pour mes besoins. Parfois, pour des raisons de performances ou parce que vous n’avez pas un accès facile à un DOM, vous voudrez peut-être simplement une calculatrice autonome hacky calibrée avec une seule police. Alors, voici un modèle calibré à Helvetica; passer une chaîne et (éventuellement) une taille de police:

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
}

Ce tableau moche géant est composé de ASCII largeurs de caractères indexées par le code de caractères. Donc, cela ne supporte que ASCII (sinon, on suppose une largeur de caractère moyenne). Heureusement, la largeur est fondamentalement linéaire avec la taille de la police. Elle convient donc parfaitement à toutes les tailles de police. Il manque visiblement toute conscience de crénage, de ligatures ou autre.

Pour "calibrer", je viens de rendre chaque caractère jusqu'à charCode 126 (le puissant tilde) sur un svg et j'ai récupéré le cadre de sélection et l'ai sauvegardé dans ce tableau; plus de code et explication et démo ici .

7
Toph

Vous pouvez utiliser le canevas pour ne pas trop vous préoccuper des propriétés 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;
5
rysama
<span id="text">Text</span>

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

Cela devrait fonctionner tant que la balise <span> ne contient pas d'autres styles . OffsetWidth inclura la largeur des bordures, le remplissage horizontal, la largeur de la barre de défilement verticale, etc. 

4
Bryan Friedman

Le code-snips ci-dessous "calcule" la largeur de la balise span et y ajoute "..." s'il est trop long et réduit la longueur du texte un millier de fois)

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 (avec 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

Essayez ce code:

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

En me basant sur Réponse de Deepak Nadar , j'ai modifié le paramètre de fonction pour accepter les styles de texte et de police. Vous n'avez pas besoin de référencer un élément. De plus, les fontOptions ont des valeurs par défaut, vous n'avez donc pas besoin de toutes les fournir.

(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

Le mieux est de détecter si le texte est bien ajusté avant d'afficher l'élément. Ainsi, vous pouvez utiliser cette fonction qui n'exige pas que l'élément soit à l'écran.

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

Usage:

if ( textWidth("Text", "bold 13px Verdana") > elementWidth) {
    ...
}
1
artnikpro

La largeur et la hauteur d'un texte peuvent être obtenues avec clientWidth et clientHeight

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

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

assurez-vous que la propriété de position de style est définie sur absolue

element.style.position = "absolute";

pas nécessaire d'être à l'intérieur d'une div, peut être à l'intérieur d'une p ou d'une span

1
Gjaa

Je suppose que cela ressemble beaucoup à l’entrée de Depak, mais est basé sur le travail de Louis Lazaris publié dans un article de impressionnant pages Web

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

L'événement fit est utilisé pour exécuter l'appel de fonction immédiatement après que la fonction est associée au contrôle.

par exemple: $ ('input'). autofit (). trigger ("fit");

0
Mauricio

Fiddle de l'exemple de travail: 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>

Code 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

Si quelqu'un d'autre cherchait à la fois un moyen de mesurer la largeur d'une chaîne et un moyen de savoir quelle est la taille de police la plus grande pouvant contenir une largeur donnée, voici une fonction qui s'appuie sur la solution de @ Domi avec une recherche binaire:

/**
 * 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;
        }
    }
}
0
M Katz

La méthode Element.getClientRects() renvoie une collection d'objets DOMRect qui indiquent les rectangles de délimitation de chaque zone de bordure CSS d'un client. La valeur renvoyée est une collection d'objets DOMRect, une pour chaque zone de bordure CSS associée à l'élément. Chaque objet DOMRect contient les propriétés left, top, right et bottom en lecture seule décrivant la zone de bordure, en pixels, avec le coin supérieur gauche par rapport au haut gauche de la fenêtre.

Element.getClientRects () by Mozilla Contributors est sous licence de CC-BY-SA 2.5 .

La somme de toutes les largeurs de rectangle renvoyées donne la largeur totale du texte en pixels.

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

Sans 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

J'ai créé un petit module ES6 (utilisant 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();
}

Facile à utiliser:

import stringWidth from './string_width';
const w = stringWidth('1-3', {fontSize: 12, padding: 5});

Ce qui est cool, vous remarquerez peut-être - cela permet de prendre en compte tous les attributs CSS, même les rembourrages!

0
Roman86