默认情况下,<input>
和 <textarea>
元素不会根据其包含的内容更改大小。 实际上,没有任何简单的 HTML 或 CSS 方法可以使它们这样做。 有点滑稽,因为这似乎是一个合理的用例。 但是当然,我的朋友,总有方法。 总有方法。
Remy Sharp 最近在 博客中 提到了这个问题,当时他谈到内联 <input>
元素。
非输入元素会自然扩展
对我来说很奇怪,没有办法强制输入元素模仿这种行为,但事实就是这样。
我们可以使用 contenteditable
属性将任何元素设置为可编辑和类似输入框。
<span
class="input"
role="textbox"
contenteditable>
99
</span>
该 <span>
会自然扩展到其包含内容所需的大小。 如果它是 <div>
或任何其他块级元素,它也会根据需要垂直扩展。
但非输入元素是否可访问?
我不确定。 请注意,我在元素上添加了 role="textbox"
。 这只是根据 一些文档 作出的最佳猜测。
即使这有帮助...
- 表单可以用 Enter 键提交怎么办?
- 表单数据通常会被序列化并发送,而执行此操作的代码可能不会查找 span 元素。
- 它在屏幕阅读器中实际上读取起来与输入框一样吗?
- 输入框自然会做哪些其他事情¹ ,而我没有想到?
虽然我对能够从浏览器中免费获得自动调整大小的想法感到很兴奋,但我也对(我)未知的可用性和可访问性风险感到担忧。
调整实际输入元素的大小
因此,假设我们坚持使用 <input>
和 <textarea>
。 即使这并不自然,我们能使它们可调整大小吗?
我有一个想法,就是将输入框包裹在一个相对内联的父元素中,并将其绝对定位在其中。 然后,使用 JavaScript,我们可以将输入框的值与该包装器中的隐藏 span 同步,根据需要将宽度推宽。
对于文本域,一种经典的技术是统计换行符的数量,使用该数字设置高度,然后乘以行高。 这对于预格式化的文本(如代码)非常有效,但对于长篇类似段落的文本则完全无效。
以下是我将这些想法结合在一起的结果。
其他想法
Shaw 写了一行非常巧妙的 JavaScript 代码。 该 JavaScript 代码将 data-*
属性设置为与输入框的值相等。 输入框被设置为在一个 CSS 网格中,该网格是一个伪元素,它使用 data-*
属性作为其内容。 该内容根据输入框值拉伸网格到合适的大小。
您的想法
我绝对知道,你们这些网络极客们已经想出了六种方法来解决这个问题。 让我们在评论区看看你们的方案。
- Eric Bailey 立即给我提供了一些想法:(1)没有可访问的名称。(2)它可能不适用于语音控制。(3)它将在高对比度模式下被忽略。
Shaw 使用 CSS 网格的这一行代码真是天才! 它有什么缺点或副作用吗? 我想,在实际布局中使用它之前,我们不会知道,但对我来说,它似乎还不错。
FWIW,我在 大约 8 年前 创建了一个解决方案(Chris,你甚至评论了它!),它使用一个克隆的 div 元素,我从这个元素中“借用”了文本域的大小。 我最近对其进行了更新,不再使用 jQuery,而是使用更现代的 JS(尽管它仍然包含一些旧的 IE 代码,你可以将其删除)。 这里有 CodePen。
使用 ::before 或 ::after 可能是一个问题。 具体取决于你的浏览器和屏幕阅读器组合,生成的內容可能会被朗读。 对于独立的 html 元素,你可以设置 aria-hidden 属性来阻止这种情况,例如第一个示例中那样。
SPAN 方法非常有用,我正在使用它,但有一个问题。 复制和粘贴会将一个 span 粘贴到块中。 我会考虑通过 onkeydown 或其他方法进行编辑,但这很奇怪,因为 span 不会简单地粘贴到编辑器中,而只会粘贴模拟文本域的 span。 如果有人有解决方案,请告诉我。
使用了一种方法,在文本域上设置
overflow-y: hidden;
,然后使用 eventHandler 监听input
事件,然后使用 scrollHeight 值更新 Height 样式。不要忘记在页面加载/DOM 插入时也设置高度。
我使用了一个修改版本,我从网上多个来源拼凑而来,只做了一些细微调整。
它有点笨拙,因为我没有让它检查动态创建的元素,所以我添加了“mousedown”事件。
此外,为了简洁起见,这是 jQuery 版本。
如果有人有改进建议,请告诉我。 我不喜欢 hack 技巧,所以我真的不愿意使用文章中的示例。
也许这需要一个简单的浏览器功能? 或者一个 CSS 扩展?
觉得有必要为此创建一个 codepen。(我从上面的评论中稍微调整了一下)
这很好,虽然并不完美。“单击/聚焦时扩展”示例扩展的高度远远超过了它需要的程度(至少在我的 Chrome/Windows 10 浏览器上)。“边输入边扩展”示例的行为更好,但有时它在末尾会有一行空白,有时则没有(似乎取决于输入的文本)。 但总体来说,我喜欢你的解决方案,比我的好。
我的解决方案是创建一个隐藏的 DIV,其宽度、边框、边距、填充、字体大小、行高等与 TEXTBOX 相同,将 TEXTBOX 的内容复制到 DIV 中,然后测量 DIV 的高度并将该高度应用于 TEXTBOX。
你的解决方案的好处是不需要辅助 DIV。
好的,使用滚动高度真是天才。 我一定会借鉴这个概念!
好的,我决定在我的 Vue 项目中使用这种方法。 我还通过观察文本域的 max-height 的计算值来动态设置/移除 overflow,以防止滚动条闪烁。 这里一个关键点是设置 rows=”1”,这似乎默认设置为 2,因此当你删除所有行时,可以返回到初始高度。 这或多或少满足了所有要求,包括完全响应性。
查看 Ian 的 Pen 自动调整高度的文本域。
(@iancwoodward) 在 CodePen 上。
这里有很多不错的想法,每个都有各自的优缺点。我认为,选择最适合项目的方案才是最好的,几乎没有一个问题只有一个解决方案。
我们去年为 Colloq 构建了 原生 textarea 调整大小的 ECMAScript 类 并撰写了相关内容。同样比较简单有效,并且使用现代方法。
https://github.com/LeaVerou/awesomplete
几年前,我需要让一个用于弹出消息的 <DIV> 在弹出消息的输出文本超出消息框边界时扩展。
我记不起当时是怎么做的了,所以今天早上我在网上搜索相同的解决方案,然后找到了你的帖子。后来我找到了我的旧代码,并修改了它以满足我今天需求,但我随后对其进行了扩展并创建了一个演示,该演示在内容扩展时会扩展 INPUT 和 TEXTAREA HTML 元素,我可以将其发布到这里。我已经将演示推送到一个公共 GitHub 存储库。
您可以在此处找到演示
https://github.com/PaulSwarthout/Input-Expansion-Demo
JavaScript 代码位于 <HEAD></HEAD> 中。所有功能都在 input_test() {…} 函数中。
希望对某人有所帮助。
对于解决方案,是否有一个 CSS 解决方案,即粘贴的文本不会被格式化?它会以纯文本形式粘贴吗?
对于
<span>
方法,是否有一个 CSS 解决方案,即粘贴的文本不会被格式化?它会以纯文本形式粘贴吗?这是我基于巧妙的 data-* 解决方案的 web-component 版本
为什么不直接使用 .scrollWidth?
仅适用于 input
<input type="text" size="1" oninput="this.setAttribute('size',this.value.length||=1)">
很喜欢 Shaw 的解决方案,很棒!在我的应用程序中运行良好。谢谢!
在 Microsoft Teams 中,我们有类似这样的 textarea 功能,需要在 Angular 中构建相同的特性。