将输入字段的宽度调整为其输入

IT技术 javascript html css
2021-01-20 22:09:25
<html>
  <head>
  </head>
  <body>
    <input type="text" value="1" style="min-width:1px;" />
  </body>
</html>

这是我的代码,它不起作用。在 HTML、JavaScript、PHP 或 CSS 中还有其他方法可以设置最小宽度吗?

我想要一个宽度动态变化的文本输入字段,以便输入字段围绕其内容流动。每个输入都有一个内置的 填充2em,这就是问题,第二个问题是min-width根本无法处理输入。

如果我设置的宽度超过所需的宽度而不是整个程序混乱,我需要 1px 的宽度,只有在需要时才需要更多。

6个回答

在现代浏览器版本中,CSS 单元ch也可用。据我了解,它是与字体无关的单位,其中1ch等于0任何给定字体中字符(零)的宽度

因此,像下面这样简单的东西可以用作调整大小函数:

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>

该示例会将“elem”的大小调整为值的长度 + 2 个额外字符。

单位 ch 的一个潜在问题是,在许多字体(即 Helvetica)中,字符“m”的宽度超过了字符 0 的宽度,而字符“i”要窄得多。根据这篇文章,1ch 通常比平均字符宽度宽,通常宽 20-30% 左右

如果您使用等宽字体,效果会很好。对于其他字体,您的里程可能会有所不同,因为它显然使用了 0 字符的字符宽度。
2021-03-14 22:09:25
这根本不是一个好的答案,因为测量不准确并且没有考虑元素上可能出现的样式input,例如font-styleletter-spacing等等。我用现场演示编辑了答案。
2021-03-26 22:09:25
我很惊讶这条评论没有得到更高的投票,因为它是一个很好的解决方案,大约 95% ( 1 ) 的浏览器支持这一点。
2021-03-29 22:09:25
如果您将输入上的 box-sizing 设置为“content-box”,这将非常有效。这样,当您设置大小时,它会忽略填充。
2021-03-30 22:09:25
这真的很棒。尽管请注意,当.遇到a 时,它有时会出错/无法按我预期的那样工作
2021-04-02 22:09:25

听起来您的期望是根据文本框的内容将样式动态应用于文本框的宽度。如果是这样,您将需要一些 js 来运行文本框内容更改,如下所示

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

注意:此解决方案仅适用于每个字符都正好为8px宽的情况。您可以使用 CSS 单元“ch”(字符),它表示所选字体中字符“0”的宽度。你可以在这里阅读它

我同意,马塞尔(并且发布的代码并不是我真正可以看到的用途)但它表现出所需的行为。您知道如何在考虑字体、大小、粗细、字距等的情况下计算渲染文本的实际宽度吗?如果是这样,请分享,因为我有时会发现那段代码很有用。
2021-03-17 22:09:25
@Kerc & Tahbaza:是的,但这只有在每个字符的宽度正好是 8 像素时才有效。
2021-03-30 22:09:25
em 单位是字符“m”的宽度。这对于计算字符串的宽度很有用。我已经看到将 em 单位应用于某些属性的跨浏览器问题,但请对其进行测试。
2021-04-07 22:09:25
你忘记了PASTE事件,我的朋友;) 你应该把它改成onInput
2021-04-09 22:09:25
——我已经认为这只是一个例子。不过,计算输入的宽度并不难。看看我的回答。
2021-04-10 22:09:25

要计算当前输入的宽度,您必须将其嵌入到一个临时span元素中,将该东西附加到 DOM,使用该scrollWidth属性获取计算出的宽度(以像素为单位)span再次删除当然,您必须确保input在 和span元素中使用相同的字体系列、字体大小等因此,我为他们分配了相同的class。

我将函数附加到keyup事件中,因为keypress输入字符尚未添加到 input 中value,因此将导致错误的宽度。不幸的是,我不知道如何摆脱输入字段的滚动(在字段末尾添加字符时);它滚动,因为在adjustWidthOfInput()调用之前添加并显示了字符而且,如上所述,我不能反过来这样做,因为那样您将插入按下的字符之前获得输入字段的值我稍后会尝试解决这个问题。

顺便说一句,我只在 Firefox (3.6.8) 中测试过这个,但我希望你会明白这一点。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Get/set width of &lt;input&gt;</title>
    <style>
      body {
        background: #666;
      }

      .input-element {
        border: 0;
        padding: 2px;
        background: #fff;
        font: 12pt sans-serif;
      }

      .tmp-element {
        visibility: hidden;
        white-space: pre;
      }
    </style>
  </head>
  <body>
    <input id="theInput" type="text" class="input-element" value="1">
    <script>
      var inputEl = document.getElementById("theInput");

      function getWidthOfInput() {
        var tmp = document.createElement("span");
        tmp.className = "input-element tmp-element";
        tmp.innerHTML = inputEl.value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
        document.body.appendChild(tmp);
        var theWidth = tmp.getBoundingClientRect().width;
        document.body.removeChild(tmp);
        return theWidth;
      }

      function adjustWidthOfInput() {
        inputEl.style.width = getWidthOfInput() + "px";
      }

      adjustWidthOfInput();
      inputEl.onkeyup = adjustWidthOfInput;
    </script>
  </body>
</html>
我喜欢你的回答,甚至使用 jQuery/ Underscore实现了它:gist.github.com/3745941但是,我可以做一些假设:(1) 任何字符的宽度不超过 14 像素,(2) 输入元素超出元素值 14 像素是可以接受的。我把它附加到一个 keydown 事件上,它工作得很好!
2021-03-12 22:09:25
@lisak 谢谢,我调整了我的答案,但这里已经有了更好的答案。
2021-03-19 22:09:25
tmp.getBoundingClientRect().width比 好tmp.scrollWidth,因为有时会返回 0
2021-03-28 22:09:25
您应该添加white-space: pre;到CSS是这样的:.tmp-element{ visibility: hidden; white-space: pre;}否则会合并空格,宽度计算失败。<input>并且<span>在空白处理方面表现不同,<input>保留空白并将<span>连续的空白合并为一个(如果white-space: pre;不添加)。
2021-03-29 22:09:25
更好的?我不会这么说的。标记的答案缺乏准确性,其他人(+此处 1此处 2)使用 jQuery - 我不是因为 React。Canvas 无法为您提供文本高度 AFAIK。想法:空格问题也可以通过以下方式解决:.replace(/ /g, "&nbsp;")
2021-03-30 22:09:25

这里是一个解决方案,而不等宽字体需要,只用JavaScript的一个非常小的一块代码并不需要计算计算样式,甚至支持IME支持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>

使用span.text以适应文本的宽度,并让输入与position: absolute容器具有相同的大小span每次更改时复制 input 的值(您可以轻松地将这段代码更改为 vanilla JS,或使用前端框架提供的功能)。所以输入将只适合其内容的大小。

这是对 Lyth 回答的修改,其中考虑到了:

  • 删除
  • 初始化
  • 占位符

它还允许任意数量的输入字段!要查看它的实际效果:http : //jsfiddle.net/4Qsa8/

脚本:

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

HTML:

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

嗨@yarwest,感谢您的提示。您是否知道如何使用此设置调整原始脚本?(我对 Js/jquery 的了解非常有限)
2021-03-22 22:09:25
@Maxence 收听changeorinput事件就足够了
2021-03-27 22:09:25
我对 span 的 display:none 样式有问题,因为它将 span 注册为具有 0 宽度。更好地使用具有可见性的绝对定位:为跨度隐藏。
2021-03-30 22:09:25
嗨@迈克尔。您的代码效果很好,但我遇到了问题。我的领域之一是 Google place autocmplete 领域。当我从下拉菜单中选择正确的地址时,输入字段的宽度不会根据所选地址的长度而改变。有没有简单的解决方法?
2021-04-10 22:09:25