Adjust width of input field to its input

2019-01-01 10:34发布

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

This is my code and it is not working. Is there any other way in HTML, JavaScript, PHP or CSS to set minimum width?

I want a text input field with a dynamically changing width, so that the input field fluids around its contents. Every input has a built-in padding of 2em, that is the problem and second problem is that min-width ain't working on input at all.

If I set width more than it is needed than the whole program is messy, I need the width of 1px, more only if it's needed.

24条回答
千与千寻千般痛.
2楼-- · 2019-01-01 10:54

Here's a modification of Lyth's answer that takes into account:

  • Deletion
  • Initialisation
  • Placeholders

It also allows for any number of input fields! To see it in action: http://jsfiddle.net/4Qsa8/

Script:

$(document).ready(function () {
    var $inputs = $('.resizing-input');

    // Resize based on text if text.length > 0
    // Otherwise resize based on the placeholder
    function resizeForText(text) {
        var $this = $(this);
        if (!text.trim()) {
            text = $this.attr('placeholder').trim();
        }
        var $span = $this.parent().find('span');
        $span.text(text);
        var $inputSize = $span.width();
        $this.css("width", $inputSize);
    }

    $inputs.find('input').keypress(function (e) {
        if (e.which && e.charCode) {
            var c = String.fromCharCode(e.keyCode | e.charCode);
            var $this = $(this);
            resizeForText.call($this, $this.val() + c);
        }
    });

    // Backspace event only fires for keyup
    $inputs.find('input').keyup(function (e) { 
        if (e.keyCode === 8 || e.keyCode === 46) {
            resizeForText.call($(this), $(this).val());
        }
    });

    $inputs.find('input').each(function () {
        var $this = $(this);
        resizeForText.call($this, $this.val())
    });
});

Style:

.resizing-input input, .resizing-input span {
    font-size: 12px;
    font-family: Sans-serif;
    white-space: pre;
    padding: 5px;
}

HTML:

<div class="resizing-input">
    <input type="text" placeholder="placeholder"/>
    <span  style="display:none"></span>
</div>

$(document).ready(function() {
  var $inputs = $('.resizing-input');

  // Resize based on text if text.length > 0
  // Otherwise resize based on the placeholder
  function resizeForText(text) {
    var $this = $(this);
    if (!text.trim()) {
      text = $this.attr('placeholder').trim();
    }
    var $span = $this.parent().find('span');
    $span.text(text);
    var $inputSize = $span.width();
    $this.css("width", $inputSize);
  }

  $inputs.find('input').keypress(function(e) {
    if (e.which && e.charCode) {
      var c = String.fromCharCode(e.keyCode | e.charCode);
      var $this = $(this);
      resizeForText.call($this, $this.val() + c);
    }
  });

  // Backspace event only fires for keyup
  $inputs.find('input').keyup(function(e) {
    if (e.keyCode === 8 || e.keyCode === 46) {
      resizeForText.call($(this), $(this).val());
    }
  });

  $inputs.find('input').each(function() {
    var $this = $(this);
    resizeForText.call($this, $this.val())
  });
});
.resizing-input input,
.resizing-input span {
  font-size: 12px;
  font-family: Sans-serif;
  white-space: pre;
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="resizing-input">
  First:
  <input type="text" placeholder="placeholder" />
  <span style="display:none"></span>
</div>
<br>

查看更多
若你有天会懂
3楼-- · 2019-01-01 10:56

In modern browser versions, CSS unit ch is also available. To my understanding, it is font-independent unit, where 1ch equals to width of character 0 (zero) in any given font.

Thus, something as simple as following could be used as resize function:

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>

That example would resize "elem" to length of the value + 2 characters extra.

查看更多
初与友歌
4楼-- · 2019-01-01 10:57

You could do something like this

// HTML
<input id="input" type="text" style="width:3px" />
// jQuery
$(function(){
  $('#input').keyup(function(){
    $('<span id="width">').append( $(this).val() ).appendTo('body');
    $(this).width( $('#width').width() + 2 );
    $('#width').remove();
  });
});

查看更多
浅入江南
5楼-- · 2019-01-01 10:59

I just spend some time figuring out how to do it.
Actually the simplest way I found is to move input value to span just before the input, keeping input 1 symbol width. Though I can't be sure that it fit for your initial need.
Maybe it some extra code, but in react+flux based application it is quite natural solution.

查看更多
十年一品温如言
6楼-- · 2019-01-01 11:02

It's worth noting that a nice-looking resize can be done when the font is monospaced, so we can perfectly resize the input element using the ch unit.

Also in this approach we can update the width of the field by just updating a CSS variable (custom property) on input event and we should also take care of already pre-filled input on DOMContentLoaded event

Codepen demo


Markup

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

As a root variable we set --size: 0: this variable will contain the length of the input and it will be multiplied by 1ch inside the calc() expression. By default we could also set a min-width, e.g. 10ch

The Javascript part reads the length of the value inserted and updates the variable --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);
});

of course this still works even if you don't use monospaced font, but in that case you will need to change the calc() formula by multiplying the --size variable by another value (which it's strictly dependent on the font-family and font-size) different than 1ch.

查看更多
孤独寂梦人
7楼-- · 2019-01-01 11:03

Here is a plain JS and a jQuery plugin I wrote that will handle resizing an input element using a canvas and the font size / family to determine the actual string length when rendered. (only works in > IE9, chrome, safari, firefox, opera and most other major browsers that have implemented the canvas element).

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

jQuery Plugin:

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

Note: this will not handle text-transforms, line spacing and letter spacing, and probably some other text size changing properties. To handle text-transform property set and adjust the text value to match that property. The others are probably fairly straight forward. I will implement if this starts gaining some traction...

查看更多
登录 后发表回答