Calcular el ancho del texto

101

Estoy tratando de calcular el ancho del texto usando jQuery. No estoy seguro de qué, pero definitivamente estoy haciendo algo mal.

Entonces, aquí está el código:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);
Dom
fuente
Entonces, ¿de qué manera ese código no funciona? ¿Qué necesita hacer de manera diferente?
Sixten Otto

Respuestas:

142

Esto funcionó mejor para mí:

$.fn.textWidth = function(){
  var html_org = $(this).html();
  var html_calc = '<span>' + html_org + '</span>';
  $(this).html(html_calc);
  var width = $(this).find('span:first').width();
  $(this).html(html_org);
  return width;
};
Runa Kaagaard
fuente
4
+1: esto realmente mide el texto, no solo el elemento del bloque contenedor como la solución de brainreavis.
Ben
Resbaloso. +1. Parece que le falta un punto y coma en la tercera línea después '</span>', aunque no parece hacer una diferencia (funcionó con o sin él en FF9).
shmeeps
21
Sin embargo, tenga cuidado con esto ... este método desvinculará cualquier evento en los elementos secundarios.
brianreavis
He intentado usar esta función de varias maneras, pero sigue devolviendo nulo. ¿Alguien podría publicar la sintaxis de cómo se usa realmente esta función? ¿Ejecuto la función .textWidth () en un objeto jQuery? ¿Paso texto a esta función? ¿Ejecuto la función como una función jQuery (es decir, $ .textWidth (jqObject)? Porque ninguna de esas opciones parece funcionar. Gracias ...
moosefetcher
2
@moosefetcher harías $ (selector) .textWidth (); Mire aquí learn.jquery.com/plugins/basic-plugin-creation/…
uesports135
89

Aquí hay una función que es mejor que otras publicadas porque

  1. es mas corto
  2. funciona cuando se pasa una <input>, <span>o "string".
  3. es más rápido para usos frecuentes porque reutiliza un elemento DOM existente.

Demostración: http://jsfiddle.net/philfreo/MqM76/

// Calculate width of text from DOM element or string. By Phil Freo <http://philfreo.com>
$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
    $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};
philfreo
fuente
1
¡Guauu! ¡Pura genialidad!
Michel Triana
3
Gran solución, creo que debería aceptarse la respuesta! ¡Gracias compañero!
Ilia Rostovtsev
¡Fantástico! Simple y limpio.
Carey Estes
Si bien es bueno, esto no maneja espacios. Consulte la respuesta de @edsioufi para ver una mejora de esta solución.
Badgerspot
Si hay texto oculto dentro del elemento, entonces sesgará su ancho. Para tener en cuenta esto, asegúrese de eliminar los nodos ocultos antes de calcular el ancho del texto. Para eliminar de forma segura los nodos ocultos, probablemente debería hacer un clon primero y realizar la eliminación allí.
jueves
36

Mi solución

$.fn.textWidth = function(){
    var self = $(this),
        children = self.children(),
        calculator = $('<span style="display: inline-block;" />'),
        width;

    children.wrap(calculator);
    width = children.parent().width(); // parent = the calculator wrapper
    children.unwrap();
    return width;
};

Básicamente una mejora con respecto a Rune, que no se usa .htmltan a la ligera

bevacqua
fuente
Por Ajarn Gerhard, quien publicó esto como respuesta: Esto no funciona en IE8 porque le falta un /paréntesis antes del cierre de la <span>etiqueta:calculator = $('<span style="display: inline-block;" />'),
Petr R.
1
Esto parece devolver nulo si hay un elemento secundario debajo del elemento que está midiendo. ¿Se puede hacer que funcione sin el elemento hijo? Ver jsfiddle.net/h22tj/41
Casper
+1 - Nunca supe que había un desenvolver (), que me ha causado un dolor sin fin.
Orwellophile
Siempre devuelve nulo en Chrome.
emeraldhieu
12

Las textWidthfunciones proporcionadas en las respuestas y que aceptan a stringcomo argumento no tendrán en cuenta los espacios en blanco iniciales y finales (no se representan en el contenedor ficticio). Además, no funcionarán si el texto contiene algún marcado html (una subcadena <br>no producirá ningún resultado y &nbsp;devolverá la longitud de un espacio).

Esto es solo un problema para las textWidthfunciones que aceptan a string, porque si se proporciona un elemento DOM y .html()se invoca sobre el elemento, entonces probablemente no haya necesidad de arreglar esto para tal caso de uso.

Pero si, por ejemplo, está calculando el ancho del texto para modificar dinámicamente el ancho de un inputelemento de texto a medida que el usuario escribe (mi caso de uso actual), probablemente querrá reemplazar los espacios iniciales y finales con &nbsp;y codificar la cadena a html.

Usé la solución de philfreo, así que aquí hay una versión que corrige esto (con comentarios sobre adiciones):

$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').appendTo(document.body);
    var htmlText = text || this.val() || this.text();
    htmlText = $.fn.textWidth.fakeEl.text(htmlText).html(); //encode to Html
    htmlText = htmlText.replace(/\s/g, "&nbsp;"); //replace trailing and leading spaces
    $.fn.textWidth.fakeEl.html(htmlText).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};
edsioufi
fuente
Gracias. Tu respuesta es la más valiosa.
Vishal
1
Curiosamente, cuando probé este, no copió correctamente el archivo font-size. Tuve que agregar css('font-size'), this.css('font-size'))para que funcionara. ¿Alguna idea de por qué fontsolo no copia ese valor?
Gone Coding
@GoneCoding ¿Dónde agregaste esos extras?
webmagnets
@webmagnets: el mismo lugar que el .cssmétodo existente , pero veo que mis corchetes están mal. Debería ser css('font-size', this.css('font-size')).
Gone Coding
11

Las funciones de ancho de jQuery pueden ser un poco turbias al intentar determinar el ancho del texto debido a modelos de caja inconsistentes. La forma segura sería inyectar div dentro de su elemento para determinar el ancho real del texto:

$.fn.textWidth = function(){
  var sensor = $('<div />').css({margin: 0, padding: 0});
  $(this).append(sensor);
  var width = sensor.width();
  sensor.remove();
  return width;
};

Para usar este mini complemento, simplemente:

$('.calltoaction').textWidth();
brianreavis
fuente
1
¿No le daría esto el ancho del bloque en lugar del texto?
Josh Rickard
-1 De hecho, esto parece medir el ancho del cuadro en lugar del ancho del texto.
Nathan Arthur
1
¿No solucionaría simplemente el problema de ancho el uso de un intervalo en lugar de un div? Si es así, entonces esta función es un poco mejor que la respuesta aceptada.
Josh
@Josh: Si lo reemplazas con un span, obtienes cero. Probé esta solución en un H2, donde los elementos principales se han desbordado oculto, y solo obtengo la longitud truncada del texto. ¿Quizás una explicación de cómo se supone que funciona esto ayudaría a que funcione mejor?
Gone Coding
8

Encontré que esta solución funciona bien y hereda la fuente de origen antes de dimensionar:

$.fn.textWidth = function(text){
  var org = $(this)
  var html = $('<span style="postion:absolute;width:auto;left:-9999px">' + (text || org.html()) + '</span>');
  if (!text) {
    html.css("font-family", org.css("font-family"));
    html.css("font-size", org.css("font-size"));
  }
  $('body').append(html);
  var width = html.width();
  html.remove();
  return width;
}
Vince Spicer
fuente
1
Terminé usando esto, pero agregué org.css("font-weight"). Además, diría que la if(!text)parte no es intuitiva. Si utilizo, por ejemplo, jQuery("#someContainer").textWidth("Lorem ipsum")me gustaría saber el ancho del texto de "Lorem ipsum" cuando se aplica en ese contenedor en particular.
Sleavely
8

Ni Rune ni Brain funcionaban para mí en caso de que el elemento que sostenía el texto tuviera un ancho fijo. Hice algo similar a Okamera. Utiliza menos selectores.

EDITAR: Probablemente no funcione para elementos que usan relativo font-size, ya que el siguiente código inserta el htmlCalcelemento en, por lo bodytanto, pierde la información sobre la relación de los padres.

$.fn.textWidth = function() {
    var htmlCalc = $('<span>' + this.html() + '</span>');
    htmlCalc.css('font-size', this.css('font-size'))
            .hide()
            .prependTo('body');
    var width = htmlCalc.width();
    htmlCalc.remove();
    return width;
};
chmurson
fuente
Esta fue la mejor solución para mí con el soporte de IE8 y no romperá ningún vínculo con el elemento en el proceso. Gracias.
ouija
nota: En un método de extensión jQuery, thisya es un objeto jQuery, por lo que $(this)es redundante.
Gone Coding
Esto funcionó mal para mí, ya que el ancho calculado es demasiado pequeño. La respuesta aceptada funcionó correctamente
PandaWood
5

Si intentas hacer esto con texto en un cuadro de selección o si esos dos no funcionan, prueba este en su lugar:

$.fn.textWidth = function(){
 var calc = '<span style="display:none">' + $(this).text() + '</span>';
 $('body').append(calc);
 var width = $('body').find('span:last').width();
 $('body').find('span:last').remove();
 return width;
};

o

function textWidth(text){
 var calc = '<span style="display:none">' + text + '</span>';
 $('body').append(calc);
 var width = $('body').find('span:last').width();
 $('body').find('span:last').remove();
 return width;
};

si quieres tomar el texto primero

okamera
fuente
4

Lo que está haciendo mal es que está llamando a un método en cTxt, que es una cadena simple y no un objeto jQuery. cTxt es realmente el texto contenido.

Juraj Blahunka
fuente
2

Ligero cambio a Nico, ya que .children () devolverá un conjunto vacío si hacemos referencia a un elemento de texto como h1 o p . Entonces usaremos .contents () en su lugar, y usaremos esto en lugar de $ (this) ya que estamos creando un método en un objeto jQuery.

$.fn.textWidth = function(){
    var contents = this.contents(),
        wrapper  = '<span style="display: inline-block;" />',
        width    = '';

    contents.wrapAll(wrapper);
    width = contents.parent().width(); // parent is now the wrapper
    contents.unwrap();
    return width;
    };
309 diseñador
fuente
1

Después de perseguir a un fantasma durante dos días, tratando de averiguar por qué el ancho de un texto era incorrecto, me di cuenta de que se debía a los espacios en blanco en la cadena de texto que detenían el cálculo del ancho.

por tanto, otro consejo es comprobar si los espacios en blanco están causando problemas. utilizar

&nbsp;

espacio sin rupturas y ver si eso lo arregla.

las otras funciones sugeridas por la gente también funcionan bien, pero son los espacios en blanco los que causan problemas.

zonabi
fuente
Simplemente agregue temporalmente white-space: nowrapal CSS en línea para evitar esto.
Gone Coding
1

Si está tratando de determinar el ancho de una combinación de nodos de texto y elementos dentro de un elemento dado, necesita envolver todo el contenido con wrapInner () , calcular el ancho y luego desenvolver el contenido.

* Nota: También necesitará extender jQuery para agregar una función unsrapInner () ya que no se proporciona por defecto.

$.fn.extend({
  unwrapInner: function(selector) {
      return this.each(function() {
          var t = this,
              c = $(t).children(selector);
          if (c.length === 1) {
              c.contents().appendTo(t);
              c.remove();
          }
      });
  },
  textWidth: function() {
    var self = $(this);
    $(this).wrapInner('<span id="text-width-calc"></span>');
    var width = $(this).find('#text-width-calc').width();
    $(this).unwrapInner();
    return width;
  }
});
trip41
fuente
+1 para .wrapInner. Como probablemente sepa, tratar con elementos de texto puro en jQuery es un infierno. Si hay otros métodos de jQuery que sean aplicables, hágamelo saber. He tenido que recurrir a .get (0) .children y no es bonito.
Orwellophile
1

Ampliando la respuesta de @ philfreo:

Agregué la capacidad de verificar text-transform, ya que cosas como text-transform: uppercasegeneralmente tienden a ensanchar el texto.

$.fn.textWidth = function (text, font, transform) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
    $.fn.textWidth.fakeEl.text(text || this.val() || this.text())
        .css('font', font || this.css('font'))
        .css('text-transform', transform || this.css('text-transform'));
    return $.fn.textWidth.fakeEl.width();
};
shaneparsons
fuente
0
var calc = '<span style="display:none; margin:0 0 0 -999px">' + $('.move').text() + '</span>';
yura
fuente
0

Llame a getColumnWidth () para obtener el texto. Esto funciona perfectamente bien.

someFile.css
.columnClass { 
    font-family: Verdana;
    font-size: 11px;
    font-weight: normal;
}


function getColumnWidth(columnClass,text) { 
    tempSpan = $('<span id="tempColumnWidth" class="'+columnClass+'" style="display:none">' + text + '</span>')
          .appendTo($('body'));
    columnWidth = tempSpan.width();
    tempSpan.remove();
return columnWidth;
}

Nota: - Si desea .css en línea, pase los detalles de la fuente solo en estilo.

Arun Pratap Singh
fuente
0

Modifiqué el código de Nico para que funcionara según mis necesidades.

$.fn.textWidth = function(){
    var self = $(this),
        children = self.contents(),
        calculator = $('<span style="white-space:nowrap;" />'),
        width;

    children.wrap(calculator);
    width = children.parent().width(); // parent = the calculator wrapper
    children.unwrap();
    return width;
};

Estoy usando .contents () ya que .children () no devuelve los nodos de texto que necesitaba. También descubrí que el ancho devuelto se vio afectado por el ancho de la ventana gráfica que estaba causando el ajuste, así que estoy usando espacio en blanco: nowrap; para obtener el ancho correcto independientemente del ancho de la ventana gráfica.

non_carbondated
fuente
0
$.fn.textWidth = function(){
        var w = $('body').append($('<span stlye="display:none;" id="textWidth"/>')).find('#textWidth').html($(this).html()[0]).width();
        $('#textWidth').remove();
        console.log(w);
        return w;
    };

casi una línea. Te da el con del primer personaje

ceed
fuente
0

No pude hacer que ninguna de las soluciones enumeradas funcionara al 100%, así que se me ocurrió este híbrido , basado en ideas de @chmurson (que a su vez se basó en @Okamera) y también de @philfreo:

(function ($)
{
    var calc;
    $.fn.textWidth = function ()
    {
        // Only create the dummy element once
        calc = calc || $('<span>').css('font', this.css('font')).css({'font-size': this.css('font-size'), display: 'none', 'white-space': 'nowrap' }).appendTo('body');
        var width = calc.html(this.html()).width();
        // Empty out the content until next time - not needed, but cleaner
        calc.empty();
        return width;
    };
})(jQuery);

Notas:

  • thisdentro de un método de extensión jQuery ya es un objeto jQuery, por lo que no es necesario todo lo extra $(this)que tienen muchos ejemplos.
  • Solo agrega el elemento ficticio al cuerpo una vez y lo reutiliza.
  • También debe especificar white-space: nowrap, solo para asegurarse de que lo mida como una sola línea (y no un ajuste de línea basado en otro estilo de página).
  • No pude hacer que esto funcionara fontsolo y tuve que copiar explícitamente font-sizetambién. No estoy seguro de por qué todavía (todavía estoy investigando).
  • Esto no admite campos de entrada de esa manera @philfreo.
Codificación ido
fuente
0

A veces también necesita medir adicionalmente la altura y no solo el texto , sino también el ancho de HTML . Tomé la respuesta de @philfreo y la hice más flexible y útil:

function htmlDimensions(html, font) {
  if (!htmlDimensions.dummyEl) {
    htmlDimensions.dummyEl = $('<div>').hide().appendTo(document.body);
  }
  htmlDimensions.dummyEl.html(html).css('font', font);
  return {
    height: htmlDimensions.dummyEl.height(),
    width: htmlDimensions.dummyEl.width()
  };
}
Daniel Kmak
fuente
0

el ancho del texto puede ser diferente para diferentes padres, por ejemplo, si agrega un texto en la etiqueta h1, será más ancho que div o etiqueta, por lo que mi solución es la siguiente:

<h1 id="header1">

</h1>

alert(calcTextWidth("bir iki", $("#header1")));

function calcTextWidth(text, parentElem){
    var Elem = $("<label></label>").css("display", "none").text(text);
    parentElem.append(Elem);
  var width = Elem.width();
  Elem.remove();
    return width;
}
Saeed Taran
fuente
0

Tuve problemas con soluciones como las de @ rune-kaagaard para grandes cantidades de texto. Descubrí esto:

$.fn.textWidth = function() {
	var width = 0;
	var calc = '<span style="display: block; width: 100%; overflow-y: scroll; white-space: nowrap;" class="textwidth"><span>' + $(this).html() + '</span></span>';
	$('body').append(calc);
	var last = $('body').find('span.textwidth:last');
	if (last) {
			var lastcontent = last.find('span');
			width = lastcontent.width();
			last.remove();
	}
	return width;
};

JSFiddle GitHub

peeto
fuente
-1

creo que deberías usar $('.calltoaction').val;

Además, estaría usando id (#) en lugar de una clase para eso ... si tienes más de una de esas clases, ¿cómo lo manejaría?

Noam Smadja
fuente
Sí, hay más de uno en el documento. ¿Por qué sugerirías id?
Dom