Existe uma maneira de dimensionar a largura de um <input type="text">
para a largura do valor real?
input {
display: block;
margin: 20px;
width: auto;
}
<input type="text" value="I've had enough of these damn snakes, on this damn plane!" />
<input type="text" value="me too" />
Respostas:
Você pode fazer isso da maneira fácil, definindo o
size
atributo para o comprimento do conteúdo de entrada:function resizeInput() { $(this).attr('size', $(this).val().length); } $('input[type="text"]') // event handler .keyup(resizeInput) // resize on page load .each(resizeInput);
Veja: http://jsfiddle.net/nrabinowitz/NvynC/
Isso parece adicionar algum preenchimento à direita que suspeito ser dependente do navegador. Se você quiser que seja realmente adequado para a entrada, você pode usar uma técnica como a que descrevo nesta resposta relacionada , usando jQuery para calcular o tamanho do pixel do seu texto.
fonte
Courier New
fonte para caixa de texto, porque a largura de todos os caracteres nesta fonte é igual. ( jsfiddle.net/NabiKAZ/NvynC/745 )UMA SOLUÇÃO SIMPLES, MAS PIXEL PERFEITA
Já vi várias maneiras de fazer isso, mas o cálculo da largura das fontes nem sempre é 100% preciso, é apenas uma estimativa.
Consegui criar uma forma perfeita de pixel de ajustar a largura de entrada, tendo um espaço reservado oculto para medir.
jQuery (recomendado)
$(function(){ $('#hide').text($('#txt').val()); $('#txt').width($('#hide').width()); }).on('input', function () { $('#hide').text($('#txt').val()); $('#txt').width($('#hide').width()); });
body, #txt, #hide{ font:inherit; margin:0; padding:0; } #txt{ border:none; color:#888; min-width:10px; } #hide{ display:none; white-space:pre; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p>Lorem ipsum <span id="hide"></span><input id="txt" type="text" value="type here ..."> egestas arcu. </p>
JavaScript puro
Não fui capaz de determinar como o jQuery calcula a largura dos elementos ocultos, então um leve ajuste no css foi necessário para acomodar essa solução.
var hide = document.getElementById('hide'); var txt = document.getElementById('txt'); resize(); txt.addEventListener("input", resize); function resize() { hide.textContent = txt.value; txt.style.width = hide.offsetWidth + "px"; }
body, #txt, #hide { font: inherit; margin: 0; padding: 0; } #txt { border: none; color: #888; min-width: 10px; } #hide { position: absolute; height: 0; overflow: hidden; white-space: pre; }
<p>Lorem ipsum <span id="hide"></span><input id="txt" type="text" value="type here ..."> egestas arcu. </p>
fonte
hide
deve ter o mesmo preenchimento), aheight: 0;
parte não funcionará corretamente. Uma solução alternativa para esse problema seria usarposition: fixed; top: -100vh;
, você também pode adicionaropacity: 0;
apenas por segurança.Se por algum motivo as outras soluções não funcionarem para você, você pode usar um contenteditable-span em vez de um elemento de entrada.
<span contenteditable="true">dummy text</span>
Observe que isso é mais um hack e tem a grave desvantagem de permitir a entrada de HTML totalmente não-higienizado, como permitir que os usuários insiram (e colem) quebras de linha, links e outros HTML.
Portanto, você provavelmente não deve usar esta solução, a menos que esteja limpando cuidadosamente a entrada ...
Atualização : você provavelmente deseja usar a solução DreamTeK abaixo .
fonte
contenteditable
é para configurar um editor de texto WYSIWYG rich-text. Não para redimensionar as entradas.Editar : O plugin agora funciona com caracteres de espaço em branco à direita. Obrigado por apontar isso @JavaSpyder
Como a maioria das outras respostas não correspondia ao que eu precisava (ou simplesmente não funcionava), modifiquei a resposta de Adrian B em um plugin jQuery adequado que resulta em um dimensionamento perfeito de pixel de entrada sem exigir que você altere seu css ou html.
Exemplo: https://jsfiddle.net/587aapc2/
Uso:
$("input").autoresize({padding: 20, minWidth: 20, maxWidth: 300});
Plugar:
//JQuery plugin: $.fn.textWidth = function(_text, _font){//get width of text with font. usage: $("div").textWidth(); var fakeEl = $('<span>').hide().appendTo(document.body).text(_text || this.val() || this.text()).css({font: _font || this.css('font'), whiteSpace: "pre"}), width = fakeEl.width(); fakeEl.remove(); return width; }; $.fn.autoresize = function(options){//resizes elements based on content size. usage: $('input').autoresize({padding:10,minWidth:0,maxWidth:100}); options = $.extend({padding:10,minWidth:0,maxWidth:10000}, options||{}); $(this).on('input', function() { $(this).css('width', Math.min(options.maxWidth,Math.max(options.minWidth,$(this).textWidth() + options.padding))); }).trigger('input'); return this; } //have <input> resize automatically $("input").autoresize({padding:20,minWidth:40,maxWidth:300});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input value="i magically resize"> <br/><br/> called with: $("input").autoresize({padding: 20, minWidth: 40, maxWidth: 300});
fonte
font
é uma abreviação de CSS (estranhamente o FF não consegue lidar com isso ). Você pode corrigir isso através da definição na primeira função:var _this_font = [this.css('font-style'), this.css('font-variant'), this.css('font-weight'), 'normal', this.css('font-size') + ' / ' + this.css('line-height'), this.css('font-family')].join(' ');
. Então mudethis.css('font')
para ser_this_font
.Eu tenho um plugin jQuery no GitHub: https://github.com/MartinF/jQuery.Autosize.Input
Ele espelha o valor da entrada, calcula a largura e o usa para definir a largura da entrada.
Você pode ver um exemplo ao vivo aqui: http://jsfiddle.net/mJMpw/2175/
Exemplo de como usá-lo (porque algum código é necessário ao postar um link jsfiddle):
<input type="text" value="" placeholder="Autosize" data-autosize-input='{ "space": 40 }' /> input[type="data-autosize-input"] { width: 90px; min-width: 90px; max-width: 300px; transition: width 0.25s; }
Você apenas usa css para definir a largura mín. / Máx. E usa uma transição na largura se quiser um bom efeito.
Você pode especificar o espaço / distância até o final como o valor em notação json para o atributo data-autosize-input no elemento de entrada.
Claro, você também pode inicializá-lo usando jQuery
$("selector").autosizeInput();
fonte
Já existem muitas respostas boas aqui. Por diversão, implementei a solução abaixo, com base nas outras respostas e nas minhas próprias ideias.
<input class="adjust">
O elemento de entrada é ajustado com precisão de pixel e um deslocamento adicional pode ser definido.
function adjust(elements, offset, min, max) { // Initialize parameters offset = offset || 0; min = min || 0; max = max || Infinity; elements.each(function() { var element = $(this); // Add element to measure pixel length of text var id = btoa(Math.floor(Math.random() * Math.pow(2, 64))); var tag = $('<span id="' + id + '">' + element.val() + '</span>').css({ 'display': 'none', 'font-family': element.css('font-family'), 'font-size': element.css('font-size'), }).appendTo('body'); // Adjust element width on keydown function update() { // Give browser time to add current letter setTimeout(function() { // Prevent whitespace from being collapsed tag.html(element.val().replace(/ /g, ' ')); // Clamp length and prevent text from scrolling var size = Math.max(min, Math.min(max, tag.width() + offset)); if (size < max) element.scrollLeft(0); // Apply width to element element.width(size); }, 0); }; update(); element.keydown(update); }); } // Apply to our element adjust($('.adjust'), 10, 100, 500);
O ajuste é suavizado com uma transição CSS.
.adjust { transition: width .15s; }
Aqui está o violino . Espero que isso possa ajudar outras pessoas que procuram uma solução limpa.
fonte
Em vez de tentar criar um div e medir sua largura, acho mais confiável medir a largura diretamente usando um elemento de tela que é mais preciso.
function measureTextWidth(txt, font) { var element = document.createElement('canvas'); var context = element.getContext("2d"); context.font = font; return context.measureText(txt).width; }
Agora você pode usar isso para medir qual deve ser a largura de algum elemento de entrada em qualquer ponto no tempo, fazendo o seguinte:
// assuming inputElement is a reference to an input element (DOM, not jQuery) var style = window.getComputedStyle(inputElement, null); var text = inputElement.value || inputElement.placeholder; var width = measureTextWidth(text, style.font);
Isso retorna um número (possivelmente um ponto flutuante). Se quiser considerar o preenchimento, você pode tentar o seguinte:
var desiredWidth = (parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + Math.ceil(width) + 1 + // extra space for cursor parseInt(style.paddingRight) + parseInt(style.borderRightWidth)) inputElement.style.width = desiredWidth + "px";
fonte
Encontrei outra solução para este problema que não envolve JS. Em HTML, acabei de colocar algo como:
<div> <input class="input" value={someValue} /> <div class="ghost-input">someValue</div> </div>
Tudo o que é necessário é definir a visibilidade: oculto na entrada fantasma e largura: 100% na própria entrada. Funciona porque a entrada é dimensionada para 100% de seu contêiner, cuja largura é calculada pelo próprio navegador (com base no mesmo texto).
Se você adicionar algum preenchimento e borda ao campo de entrada, terá que ajustar sua classe de entrada fantasma de acordo (ou usar calc () na classe de entrada).
fonte
Você pode resolver este problema aqui :) http://jsfiddle.net/MqM76/217/
HTML:
<input id="inpt" type="text" /> <div id="inpt-width"></div>
JS:
$.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(); }; $('#inpt').on('input', function() { var padding = 10; //Works as a minimum width var valWidth = ($(this).textWidth() + padding) + 'px'; $('#'+this.id+'-width').html(valWidth); $('#inpt').css('width', valWidth); }).trigger('input');
fonte
Infelizmente, o
size
atributo não funcionará muito bem. Haverá espaço extra e muito pouco às vezes, dependendo de como a fonte está configurada. (veja o exemplo)Se você quiser que isso funcione bem, tente observar as alterações na entrada e redimensione-a. Você provavelmente deseja configurá-lo para as entradas
scrollWidth
. Teríamos de levar em consideração o tamanho da caixa também.No exemplo a seguir, estou definindo o
size
da entrada como 1 para evitar que tenha umscrollWidth
que seja maior do que nossa largura inicial (definido manualmente com CSS).// (no-jquery document.ready) function onReady(f) { "complete" === document.readyState ? f() : setTimeout(onReady, 10, f); } onReady(function() { [].forEach.call( document.querySelectorAll("input[type='text'].autoresize"), registerInput ); }); function registerInput(el) { el.size = 1; var style = el.currentStyle || window.getComputedStyle(el), borderBox = style.boxSizing === "border-box", boxSizing = borderBox ? parseInt(style.borderRightWidth, 10) + parseInt(style.borderLeftWidth, 10) : 0; if ("onpropertychange" in el) { // IE el.onpropertychange = adjust; } else if ("oninput" in el) { el.oninput = adjust; } adjust(); function adjust() { // reset to smaller size (for if text deleted) el.style.width = ""; // getting the scrollWidth should trigger a reflow // and give you what the width would be in px if // original style, less any box-sizing var newWidth = el.scrollWidth + boxSizing; // so let's set this to the new width! el.style.width = newWidth + "px"; } }
* { font-family: sans-serif; } input.autoresize { width: 125px; min-width: 125px; max-width: 400px; } input[type='text'] { box-sizing: border-box; padding: 4px 8px; border-radius: 4px; border: 1px solid #ccc; margin-bottom: 10px; }
<label> Resizes: <input class="autoresize" placeholder="this will resize" type='text'> </label> <br/> <label> Doesn't resize: <input placeholder="this will not" type='text'> </label> <br/> <label> Has extra space to right: <input value="123456789" size="9" type="text"/> </label>
Acho que isso deve funcionar até mesmo no IE6, mas não acredite apenas em minha palavra.
Dependendo do seu caso de uso, pode ser necessário vincular a função de ajuste a outros eventos. Por exemplo, alterar o valor de uma entrada programaticamente ou alterar a
display
propriedade de estilo do elemento denone
(ondescrollWidth === 0
) parablock
ouinline-block
, etc.fonte
Meu plugin jQuery funciona para mim:
Uso:
$('form input[type="text"]').autoFit({ });
Código-fonte de
jquery.auto-fit.js
:; (function ($) { var methods = { init: function (options) { var settings = $.extend(true, {}, $.fn.autoFit.defaults, options); var $this = $(this); $this.keydown(methods.fit); methods.fit.call(this, null); return $this; }, fit: function (event) { var $this = $(this); var val = $this.val().replace(' ', '-'); var fontSize = $this.css('font-size'); var padding = $this.outerWidth() - $this.width(); var contentWidth = $('<span style="font-size: ' + fontSize + '; padding: 0 ' + padding / 2 + 'px; display: inline-block; position: absolute; visibility: hidden;">' + val + '</span>').insertAfter($this).outerWidth(); $this.width((contentWidth + padding) + 'px'); return $this; } }; $.fn.autoFit = function (options) { if (typeof options == 'string' && methods[options] && typeof methods[options] === 'function') { return methods[options].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof options === 'object' || !options) { // Default to 'init' return this.each(function (i, element) { methods.init.apply(this, [options]); }); } else { $.error('Method ' + options + ' does not exist on jquery.auto-fit.'); return null; } }; $.fn.autoFit.defaults = {}; })(this['jQuery']);
fonte
Os elementos de entrada se comportam de maneira diferente de outros elementos, o que faria exatamente o que você deseja se você os desse
float: left
(consulte http://jsfiddle.net/hEvYj/5/ ). Não acho que isso seja possível sem calcular de alguma forma com JavaScript (ou seja, adicione 5px à largura por letra na caixa).fonte
A solução do usuário nrabinowitz está funcionando muito bem, mas eu uso o
keypress
evento em vez dekeyup
. Isso reduz a latência se o usuário digitar lentamente.fonte
oninput
(ouonpropertychange
para o IE legado) é o evento correto, pois eles respondem a coisas como colar com um clique com o botão direito ou selecionar "Arquivo -> colar" na barra de menu do navegadorAqui está minha modificação da solução de nrabinowitz . Eu não usei a propriedade size , porque ela não é perfeita com fontes proporcionais como @Mark observou. Minha solução coloca um elemento após sua entrada e obtém a largura contada pelo navegador (usando jQuery).
Embora eu não o teste, suponho que funcionará apenas se todas as propriedades CSS que afetam a fonte forem herdadas.
A largura de entrada muda no evento focusout , o que funciona melhor para mim. Mas você também pode usar keyup / keypress para alterar a largura da entrada ao digitar.
function resizeInput() { //Firstly take the content or placeholder if content is missing. var content = $(this).val().length > 0 ? $(this).val() : $(this).prop("placeholder"); //Create testing element with same content as input. var widthTester = $("<span>"+content+"</span>").hide(); //Place testing element into DOM after input (so it inherits same formatting as input does). widthTester.insertAfter($(this)); //Set inputs width; you may want to use outerWidth() or innerWidth() //depending whether you want to count padding and border or not. $(this).css("width",widthTester.width()+"px"); //Remove the element from the DOM widthTester.remove(); } $('.resizing-input').focusout(resizeInput).each(resizeInput);
fonte
Usando a tela, podemos calcular a largura dos elementos:
function getTextWidth(text, fontSize, fontName) { let canvas = document.createElement('canvas'); let context = canvas.getContext('2d'); context.font = fontSize + fontName; return context.measureText(text).width; }
e usá-lo no evento escolhido:
function onChange(e) { let width = getTextWidth(this.value, $(this).css('font-size'), $(this).css('font-family')); $(this.input).css('width', width); }
fonte
experimente a solução canvas measureText
css:
input{ min-width:10px!important; max-width:99.99%!important; transition: width 0.1s; border-width:1px; }
javascript:
function getWidthOfInput(input){ var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var text = input.value.length ? input.value : input.placeholder; var style = window.getComputedStyle(input); ctx.lineWidth = 1; ctx.font = style.font; var text_width = ctx.measureText(text).width; return text_width; } function resizable (el, factor) { function resize() { var width = getWidthOfInput(el); el.style.width = width + 'px'; } var e = 'keyup,keypress,focus,blur,change'.split(','); for (var i in e){ el.addEventListener(e[i],resize,false); } resize(); } $( "input" ).each( function(i){ resizable(this); });
fonte
Resolvi a largura criando uma tela e calculando o tamanho dela. é importante que o valor de entrada e a tela compartilhem os mesmos recursos de fonte (família, tamanho, peso ...)
import calculateTextWidth from "calculate-text-width"; /* requires two props "value" and "font" - defaultFont: normal 500 14px sans-serif */ const defaultText = 'calculate my width' const textFont = 'normal 500 14px sans-serif' const calculatedWidth = calculateTextWidth(defaultText, textFont) console.log(calculatedWidth) // 114.37890625
GitHub: https://github.com/ozluy/calculate-text-width CodeSandbox: https://codesandbox.io/s/calculate-text-width-okr46
fonte