如何使用CSS自动调整textarea的大小?

28

在一个起初是小框且单行的文本区域中,是否可以使用CSS使其随着用户输入多行而自动增加行数,直到达到设定的限制(300px),然后出现带有overflow属性为auto的滚动条以满足所有输入?

3个回答

18

2020年更新 - 使用contenteditable

由于这个答案仍然有时对一些人有所帮助,我觉得应该更新一下我的答案,加入Chris Coyier最新的发现。

需要注意的是,这仍然不是CSS3的解决方案。但它是内置在浏览器中的,并且可以重新创建OP所寻求的行为。

<div />上使用contenteditable HTML属性将允许用户编辑div的文本内容,并随着用户换行而扩展。然后,只需将您的div伪装成<textarea />即可。

<div 
  class="expandable-textarea"
  role="textbox"
  contenteditable
>
    Your default value
</div>

.expandable-textarea {
  border: 1px solid #ccc;
  font-family: inherit;
  font-size: inherit;
  padding: 1px 6px;

  display: block;
  width: 100%;
  overflow: hidden;
  resize: both;
  min-height: 40px;
  line-height: 20px;
}

这种解决方案有一个限制,即我们不使用文本区域(textarea)。请记住,一些功能(例如 placeholder)需要使用<div contenteditable />实现一些创意。

来源:Chris Coiyer大神的博客。链接


使用轻量级JS库的解决方法

不幸的是,似乎无法仅使用CSS3实现此功能。

但是,有一种体积为3.2k的JS替代方案可以做到。

这里是链接,包括演示和用法。

您可以通过执行 npm install autosize 来安装它,并使用以下方式:

autosize(document.querySelector('.yourTextAreaClass'));

或者使用 jQuery 风格

autosize($('.yourTextAreaClass'));

它的效果非常好。它很轻巧,使用起来自然感觉良好,不像许多做无用动画的自动调整大小插件。


能否在Angular mat-form-field中使用这个解决方案? - ranaalisaeed
1
使用 div 或 span 代替 textarea 的一个问题是你无法设置 maxlength。 - Eric Soyke

17

CodePen网站的创始人Chris Coyier最近发布了一个基于网格的纯CSS实现。原始代码来自Chris Coyier在2020年10月30日发布的CodePen

.grow-wrap {
  /* easy way to plop the elements on top of each other and have them both sized based on the tallest one's height */
  display: grid;
}

.grow-wrap::after {
  /* Note the weird space! Needed to preventy jumpy behavior */
  content: attr(data-replicated-value) " ";
  /* This is how textarea text behaves */
  white-space: pre-wrap;
  /* Hidden from view, clicks, and screen readers */
  visibility: hidden;
}

.grow-wrap>textarea {
  /* You could leave this, but after a user resizes, then it ruins the auto sizing */
  resize: none;
  /* Firefox shows scrollbar on growth, you can hide like this. */
  overflow: hidden;
}

.grow-wrap>textarea,
.grow-wrap::after {
  /* Identical styling required!! */
  border: 1px solid black;
  padding: 0.5rem;
  font: inherit;
  /* Place on top of each other */
  grid-area: 1 / 1 / 2 / 2;
}

body {
  margin: 2rem;
  font: 1rem/1.4 system-ui, sans-serif;
}

label {
  display: block;
}
<form action="#0">
  <label for="text">Text:</label>
  <div class="grow-wrap">
    <textarea name="text" id="text" onInput="this.parentNode.dataset.replicatedValue = this.value"></textarea>
  </div>
</form>

许可证:

版权所有(c)2020年 Chris Coyier (https://codepen.io/chriscoyier/pen/XWKEVLy)

特此免费授予任何获得本软件及相关文档文件(以下简称“软件”)副本的人,无限制地处理该软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售该软件的副本,并允许被授权人员这样做,但必须遵守以下条件:

所有副本或重要部分的软件必须包含上述版权声明和本许可声明。

软件是按“原样”提供的,没有任何形式的明示或暗示保证,包括但不限于适销性、特定用途的适用性和非侵权性。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任承担任何责任,无论是合同诉讼、侵权行为还是其他行为,由于软件或其使用或其他途径而引起。


1
这个文本框可以自动纵向和横向增长。有没有办法只让它纵向增长? - justadeveloper
@justadeveloper 注意 - Chris Coyier 创建了这个解决方案,所以你需要通过 Twitter 询问他或者自己在 CodePen 链接中查找。 - TylerH
感谢您的回复@TylerH。对于未来的读者:最终,我决定采用此链接中的JS解决方案:https://github.com/jackmoore/autosize - justadeveloper
1
请注意,这不是仅使用CSS的样式。JS在textarea内联。 - som

1
据我所知,仅使用CSS是不可能的,但这里有一个超级小的Angular指令,只需检查换行即可工作。您可以轻松调整它以具有最大行数等功能。
angular.module('Shared.AutoGrow.Directive', [])
.directive('autoGrow', function() {
  return {
    restrict: 'A',
    link(scope, element) {
      element.on('input change', () => {
        const text = element[0].value;
        const lines = 1 + (text.match(/\n/g) || []).length;
        element[0].rows = lines;
      });
    },
  };
});

普通的JS解决方案应该很容易推断,只需要在输入/更改元素上应用事件监听器就可以了。


1
请确保文本区域具有“height:auto”。 - Rob Audenaerde
7
只有在文本中显式地添加换行时才有效,而当文本隐式换行时则无效。 - savetheclocktower

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接