javascript Ajustar a largura do campo de entrada para sua entrada



html css (16)

Uma maneira genérica e à prova de balas deve:

  1. Leve em consideração todos os estilos possíveis do elemento de input medido
  2. Ser capaz de aplicar a medida em qualquer entrada sem modificar o HTML ou

Demo codepen

var getInputValueWidth = (function(){
  // https://stackoverflow.com/a/49982135/104380
  function copyNodeStyle(sourceNode, targetNode) {
    var computedStyle = window.getComputedStyle(sourceNode);
    Array.from(computedStyle).forEach(key => targetNode.style.setProperty(key, computedStyle.getPropertyValue(key), computedStyle.getPropertyPriority(key)))
  }
  
  function createInputMeassureElm( inputelm ){
    // create a dummy input element for measurements
    var meassureElm = document.createElement('span');
    // copy the read input's styles to the dummy input
    copyNodeStyle(inputelm, meassureElm);
    
    // set hard-coded styles needed for propper meassuring 
    meassureElm.style.width = 'auto';
    meassureElm.style.position = 'absolute';
    meassureElm.style.left = '-9999px';
    meassureElm.style.top = '-9999px';
    meassureElm.style.whiteSpace = 'pre';
    
    meassureElm.textContent = inputelm.value || '';
    
    // add the meassure element to the body
    document.body.appendChild(meassureElm);
    
    return meassureElm;
  }
  
  return function(){
    return createInputMeassureElm(this).offsetWidth;
  }
})();


// delegated event binding
document.body.addEventListener('input', onInputDelegate)

function onInputDelegate(e){
  if( e.target.classList.contains('autoSize') )
    e.target.style.width = getInputValueWidth.call(e.target) + 'px';
}
input{ 
  font-size:1.3em; 
  padding:5px; 
  margin-bottom: 1em;
}

input.type2{
  font-size: 2.5em;
  letter-spacing: 4px;
  font-style: italic;
}
<input class='autoSize' value="type something">
<br>
<input class='autoSize type2' value="here too">

https://ffff65535.com

<html>
  <head>
  </head>
  <body>
    <input type="text" value="1" style="min-width:1px;" />
  </body>
</html>

Este é o meu código e não está funcionando. Existe alguma outra maneira em HTML, JavaScript, PHP ou CSS para definir a largura mínima?

Eu quero um campo de entrada de texto com uma largura de mudança dinâmica, de modo que o campo de entrada flui em torno de seu conteúdo. Cada entrada tem um padding 2em de 2em , que é o problema e o segundo problema é que min-width não está funcionando na entrada.

Se eu definir a largura mais do que é necessário do que todo o programa é confuso, eu preciso da largura de 1px, mais apenas se for necessário.


Acho que você está interpretando mal a propriedade CSS de largura mínima . min-width é geralmente usado para definir uma largura mínima de DOM em um layout fluido, como:

input {
  width: 30%;
  min-width: 200px;
}

Isso definiria o elemento de entrada para uma largura mínima de 200 pixels. Neste contexto, "px" significa "pixels".

Agora, se você está tentando verificar se o campo de entrada contém pelo menos um caractere quando um usuário o envia, você precisará fazer alguma validação de formulário com JavaScript e PHP. Se isso é realmente o que você está tentando fazer, eu vou editar essa resposta e fazer o meu melhor para ajudá-lo.


Aqui está um JS simples e um plugin jQuery que eu escrevi que irá lidar com o redimensionamento de um elemento de entrada usando uma tela e o tamanho / família da fonte para determinar o tamanho real da string quando renderizada. (funciona apenas no> IE9, chrome, safari, firefox, opera e na maioria dos outros principais navegadores que implementaram o elemento canvas).

PlainJS:

function autoSize(input, o) {
    o || (o = {});
    o.on || (o.on = 'keyup');

    var canvas = document.createElement('canvas');
    canvas.setAttribute('style', 'position: absolute; left: -9999px');
    document.body.appendChild(canvas);

    var ctx = canvas.getContext('2d');

    input.addEventListener(o.on, function () {
        ctx.font = getComputedStyle(this,null).getPropertyValue('font');
        this.style.width = ctx.measureText(this.value + '  ').width + 'px';
    });
}

//Usage
autoSize(document.getElementById('my-input'));

Plugin jQuery:

$.fn.autoSize = function(o) {
  o = $.extend({}, {
    on: 'keyup'
  }, o);

  var $canvas = $('<canvas/>').css({position: 'absolute', left: -9999});
  $('body').append($canvas);

  var ctx = $canvas[0].getContext('2d');

  return this.on(o.on, function(){
    var $this = $(this);
    ctx.font = $this.css('font');
    $this.width(ctx.measureText($this.val()).width + 'px');
  })
}

//Usage:
$('#my-input').autoSize();

Nota: isso não manipulará transformações de texto, espaçamento de linhas e espaçamento de letras, e provavelmente algumas outras propriedades de alteração de tamanho de texto. Para manipular o conjunto de propriedades de transformação de texto e ajustar o valor de texto para corresponder a essa propriedade. Os outros provavelmente são relativamente diretos. Vou implementar se isso começar a ganhar alguma tração ...


Aqui está uma maneira alternativa de resolver isso usando um DIV e a propriedade 'contenteditable':

HTML:

<div contenteditable = "true" class = "fluidInput" data-placeholder = ""></div>

CSS: (para dar ao DIV algumas dimensões e facilitar a visualização)

.fluidInput {

    display         : inline-block;
    vertical-align  : top;

    min-width       : 1em;
    height          : 1.5em;

    font-family     : Arial, Helvetica, sans-serif;
    font-size       : 0.8em;
    line-height     : 1.5em;

    padding         : 0px 2px 0px 2px;
    border          : 1px solid #aaa;
    cursor          : text;
}


.fluidInput * {

    display         : inline;

}


.fluidInput br  {

    display         : none;

}


.fluidInput:empty:before {

    content         : attr(data-placeholder);
    color           : #ccc;

}

Nota: Se você estiver planejando usar isso dentro de um elemento FORM que pretende enviar, precisará usar Javascript / jQuery para capturar o evento submit para poder analisar o 'valor' ( .innerHTML ou .html() respectivamente) do DIV.


Aqui está uma solução sem fonte monoespaçada necessária, com apenas um pequeno código de peça de javascript , não precisa calcular estilos computados e, até mesmo suportar , textos de suporte RTL .

// copy the text from input to the span
    $(function () {
      $('.input').on('input', function () { $('.text').text($('.input').val()); });
    });
    * {
      box-sizing: border-box;
    }
    
    .container {
      display: inline-block;
      position: relative;
    }
    
    .input,
    .text {
      margin: 0;
      padding: 2px 10px;
      font-size: 24px;
      line-height: 32px;
      border: 1px solid #ccc;
      box-radius: 3px;
      height: 36px;
      font: 20px/20px sans-serif;
      /* font: they should use same font; */
    }

    .text {
      padding-right: 20px;
      display: inline-block;
      visibility: hidden;
      white-space: pre;
    }
    
    .input {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      width: 100%;
    }
    
<script src="https://code.jquery.com/jquery-3.2.0.min.js"></script>

<div class="container">
  <span class="text">
    some text
  </span>
  <input class="input" value="some text" />
</div>

Use o span.text para ajustar a largura do texto e deixe a entrada ter o mesmo tamanho com a position: absolute para o contêiner. Copie o valor da entrada para o span toda vez que ele for alterado (você pode alterar este pedaço de código para baunilha js facilmente). Assim, a entrada apenas "ajustará" o tamanho de seu conteúdo.


Com base na resposta de Michael, criei minha própria versão disso usando jQuery. Eu acho que é uma versão mais limpa / mais curta da maioria das respostas aqui e parece que o trabalho é feito.

Eu estou fazendo a mesma coisa que a maioria das pessoas aqui, usando um espaço para escrever o texto de entrada em seguida, obtendo a largura. Então eu estou definindo a largura quando as ações de chave e blur são chamados.

Aqui está um codepen trabalho. Este codepen mostra como isso pode ser usado com vários campos de entrada.

Estrutura HTML:

<input type="text" class="plain-field" placeholder="Full Name">
<span style="display: none;"></span>

jQuery:

function resizeInputs($text) {
    var text = $text.val().replace(/\s+/g, ' '),
        placeholder = $text.attr('placeholder'),
        span = $text.next('span');
        span.text(placeholder);
    var width = span.width();

    if(text !== '') {
        span.text(text);
    var width = span.width();
    }

    $text.css('width', width + 5);
};

A função acima obtém o valor de entradas, apara os espaços extras e define o texto no intervalo para obter a largura. Se não houver texto, ele recebe o espaço reservado e insere isso no intervalo. Depois de inserir o texto no intervalo, ele define a largura da entrada. O + 5 na largura é porque sem isso a entrada é cortada um pouco no navegador de borda.

$('.plain-field').each(function() {
    var $text = $(this);
    resizeInputs($text);
});

$('.plain-field').on('keyup blur', function() {
    var $text = $(this);
    resizeInputs($text);
});

$('.plain-field').on('blur', function() {
    var $text = $(this).val().replace(/\s+/g, ' ');
    $(this).val($text);
});

Se isso pudesse ser melhorado, por favor, deixe-me saber como esta é a solução mais limpa que eu poderia encontrar.


Esta é uma resposta específica do Angular, mas isso funcionou para mim e tem sido muito satisfatório em termos de simplicidade e facilidade de uso:

<input [style.width.ch]="value.length" [(ngModel)]="value" />

Ele atualiza automaticamente através das unidades de caracteres na resposta de Jani .


Eu realmente gostei da resposta de Lyth , mas também queria que:

  1. Lidar com backspace e excluir
  2. Não requer que você adicione manualmente uma tag adjacente.
  3. Aplique uma largura mínima.
  4. Automaticamente aplicado a elementos com uma classe específica

Eu adaptei seu JSFiddle e inventei this . Uma melhora não presente neste violino seria usar algo parecido com o analisador de CSS do jQuery para realmente ler a largura inicial da regra de dimensionamento automático da caixa de conexões e usá-la como minWidth. Certo, estou simplesmente usando um atributo no, que faz uma demonstração compacta, mas não é ideal. como requer um atributo extra em cada entrada. Você também pode querer apenas colocar o minWidth como 100 correto no JavaScript.

HTML:

<div id='applicationHost'>
<div>Name:   <input class='textbox-autosize' data-min-width='100' type="text" /></div>
<div>Email:  <input class='textbox-autosize' data-min-width='100' type="email" /></div>
<div>Points: <input class='textbox-autosize' data-min-width='100' type="number" /></div>
</div>

CSS:

#applicationHost {
    font-family: courier;
    white-space: pre;
}

input.textbox-autosize, span.invisible-autosize-helper {
    padding:0;
    font-size:12px;
    font-family:Sans-serif; 
    white-space:pre;
}
input.textbox-autosize {
    width: 100px; /* Initial width of textboxes */
}

/*
In order for the measurements to work out, your input and the invisible
span need to have the same styling.
*/

JavaScript:

$('#applicationHost').on('keyup', '.textbox-autosize', function(e) {
    // Add an arbitary buffer of 15 pixels.
    var whitespaceBuffer = 15;
    var je = $(this);
    var minWidth = parseInt(je.attr('data-min-width'));
    var newVal = je.val();
    var sizingSpanClass = 'invisible-autosize-helper';
    var $span = je.siblings('span.' + sizingSpanClass).first();
    // If this element hasn't been created yet, we'll create it now.
    if ($span.length === 0) {
        $span = $('<span/>', {
            'class': sizingSpanClass,
            'style': 'display: none;'
        });
        je.parent().append($span);
    }
    $span = je.siblings('span').first();
    $span.text(newVal) ; // the hidden span takes 
    // the value of the input
    $inputSize = $span.width();
    $inputSize += whitespaceBuffer;
    if($inputSize > minWidth)
        je.css("width", $inputSize) ; // apply width of the span to the input
    else
        je.css("width", minWidth) ; // Ensure we're at the min width
});

Melhor é onvalue :

<input id="txt" type="text" onvalue="this.style.width = ((this.value.length + 1) * 8) + 'px';">

Também envolve colar, arrastar e soltar, etc.


Nas versões modernas dos navegadores, a unidade CSS também está disponível. No meu entender, é uma unidade independente de fontes, em que 1ch é igual à largura do caractere 0 (zero) em qualquer fonte.

Assim, algo tão simples como o seguinte poderia ser usado como função de redimensionamento:

var input = document.querySelector('input'); // get the input element
input.addEventListener('input', resizeInput); // bind the "resizeInput" callback on "input" event
resizeInput.call(input); // immediately call the function

function resizeInput() {
  this.style.width = this.value.length + "ch";
}
input{ font-size:1.3em; padding:.5em; }
<input>

Esse exemplo redimensionaria "elem" para comprimento do valor + 2 caracteres extra.


Parece que sua expectativa é que o estilo seja aplicado dinamicamente à largura da caixa de texto com base no conteúdo da caixa de texto. Em caso afirmativo, você precisará de alguns js para serem executados na alteração do conteúdo da caixa de texto, algo assim:

<input id="txt" type="text" onkeypress="this.style.width = ((this.value.length + 1) * 8) + 'px';">

Nota: esta solução só funciona quando todos os caracteres têm exatamente 8px largura.


Por que não usar apenas css?

<div id="wrapper">
  <input onkeyup="keyup(event)">
  <div id="ghost"></div>
</div>

function keyup(e) {
	document.getElementById('ghost').innerText = e.target.value;
}
#wrapper {
  position: relative;
  min-width: 30px;
  display: inline-block;
}

input {
  position: absolute;
  left:0;
  right:0;
  border:1px solid blue;
  width: 100%;
}

#ghost {
  color: transparent;
}
<div id="wrapper">
  <input onkeyup="keyup(event)">
  <div id="ghost"></div>
</div>

wrapper {
  position: relative;
  min-width: 30px;
  border: 1px solid red;
  display: inline-block;
}

input {
  position: absolute;
  left:0;
  right:0;
  width: 100%;
}

#ghost {
  color: transparent;
}

este código foi introduzido por @Iain Todd para e eu pensei que deveria compartilhá-lo


Vale a pena notar que um resize bonito pode ser feito quando a fonte é monoespaçada, para que possamos redimensionar perfeitamente o elemento de input usando a unidade ch .

Também nessa abordagem podemos atualizar a largura do campo apenas atualizando uma variável CSS ( propriedade customizada ) no evento de input e também devemos cuidar da entrada já preenchida no evento DOMContentLoaded

Demo codepen

Marcação

<input type="text" value="space mono font" class="selfadapt" />

CSS

:root { --size: 0; }

.selfadapt {
   padding: 5px;
   min-width: 10ch;
   font-family: "space mono";
   font-size: 1.5rem;
   width: calc(var(--size) * 1ch);
}

Como uma variável raiz, definimos --size: 0 : esta variável conterá o comprimento da entrada e será multiplicada por 1ch dentro da expressão calc() . Por padrão, também podemos definir uma largura mínima, por exemplo, 10 10ch

A parte Javascript lê o tamanho do valor inserido e atualiza a variável --size :

JS

let input = document.querySelector('.selfadapt');
let root  = document.documentElement.style;

/* on input event auto resize the field */
input.addEventListener('input', function() {
   root.setProperty('--size', this.value.length );
});

/* resize the field if it is pre-populated */
document.addEventListener("DOMContentLoaded", function() {
   root.setProperty('--size', input.value.length);
});

é claro que isso ainda funciona mesmo se você não usar fonte monoespaçada, mas nesse caso você precisará alterar a fórmula calc() multiplicando a variável --size por outro valor (que é estritamente dependente da font-family da font-family e font-size ) diferente de 1ch .


Você pode fazer isso ainda mais simples em angularjs usando a diretiva ng-style embutida.

No seu html:

  <input ng-style="inputStyle(testdata)" ng-model="testdata" />

No seu controlador:

 $scope.testdata = "whatever";

 $scope.inputStyle = function(str) {
    var charWidth = 7;
    return  {"width": (str.length +1) * charWidth + "px" };
    };

Em seu css:

input { font-family:monospace; font-size:12px; }

Ajuste o charWidth para coincidir com a largura da sua fonte. Parece ser 7 em tamanho de fonte de 12px;


Você também pode definir a largura de uma entrada usando o atributo de tamanho . O tamanho de uma entrada determina sua largura em caracteres.

Uma entrada pode ajustar dinamicamente seu tamanho ouvindo os principais eventos.

Por exemplo

$("input[type='text']").bind('keyup', function () {
    $(this).attr("size", $(this).val().length );
});

JsFiddle here


PARA UM OLHAR E SENTIR NICER

Você deve usar o evento jQuery keypress () em combinação com String.fromCharCode (e.which) para obter o caractere pressionado. Daí você pode calcular qual será a sua largura. Por quê? Porque vai ficar muito mais sexy :)

Aqui está um jsfiddle que resulta em um bom comportamento comparado às soluções que usam o evento keyup: http://jsfiddle.net/G4FKW/3/

Abaixo está um JS baunilha que escuta o evento de input de um elemento <input> e define um irmão span para ter o mesmo valor de texto para medi-lo.

document.querySelector('input').addEventListener('input', onInput)

function onInput(){
    var spanElm = this.nextElementSibling;
    spanElm.textContent = this.value; // the hidden span takes the value of the input; 
    this.style.width = spanElm.offsetWidth + 'px'; // apply width of the span to the input
};
/* it's important the input and its span have same styling */
input, .measure {
    padding: 5px;
    font-size: 2.3rem;
    font-family: Sans-serif;
    white-space: pre; /* white-spaces will work effectively */
}

.measure{  
  position: absolute;
  left: -9999px;
  top: -9999px;
}
<input type="text" />
<span class='measure'></span>





css