自动增长文本区的最佳技巧

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

今年早些时候,我写了一些关于 自动增长文本区和输入 的内容。 想法是使 <textarea> 更像 <div>,以便它根据需要扩展高度以包含当前值。 它几乎很奇怪,没有一个简单的原生解决方案,不是吗? 回顾那篇文章,我的想法都不是特别好。 但 Stephen Shaw 的 想法 我在文章结尾链接到的实际上是一个 *非常* 好的主意,所以我希望能够阐明这一点并讨论它如何工作,因为它似乎是最终答案,直到我们得到一些原生和更好的东西。

如果您只想获得一个可工作的示例,请查看演示

技巧是,您需要精确地复制 <textarea> 的内容到一个 *可以* 自动扩展高度并匹配其大小的元素中。

因此,您有一个 <textarea>,它 *不能* 自动扩展高度。

相反,您需要 *精确地* 复制该元素的外观、内容和位置到另一个元素中。 您隐藏复制的元素的视觉效果(最好让技术上可用的元素保持可见)。

现在,所有三个元素都相互绑定。 哪个子元素最高,父元素的高度就会被推到该高度,另一个子元素也会随之调整。 这意味着 <textarea> 的最小高度将成为“基础”高度,但如果复制的文本元素碰巧长高了,所有元素都会随之长高。

太聪明了。 我太喜欢了。

您需要确保复制的元素 *完全* 相同

相同的字体、相同的填充、相同的边距、相同的边框……所有内容。 这是一个完全相同的副本,只是使用 visibility: hidden; 在视觉上隐藏了它。 如果它不完全相同,所有内容将不会完全按预期增长。

我们还需要在复制的文本上使用 white-space: pre-wrap;,因为这就是文本区的工作方式。

这是最奇怪的部分

在我的演示中,我使用的是 ::after 来复制文本。 我不确定这是否是最佳方法。 对我来说感觉很干净,但我想知道使用 <div aria-hidden="true"> 对屏幕阅读器是否更安全? 或者 visibility: hidden; 对此是否足够? 无论如何,这不是奇怪的部分。 这是奇怪的部分

content: attr(data-replicated-value) " ";

因为我使用的是伪元素,所以它会将 data 属性从元素中移除,并将内容渲染到页面上 **带有一个额外的空格**(这就是奇怪的部分)。 如果您没有这样做,最终结果会感觉“跳跃”。 我不能说我完全理解它,但它似乎更好地尊重了文本区和文本元素之间的换行行为。

如果您不想使用伪元素,没问题,只是要注意跳跃的行为。


Will Earp 和 Martin Tillmann 向我发来了邮件,提醒我 Shaw 的技巧是多么聪明,他们都在同一天发来邮件。 这是一个示例 Martin 使用 Alpine.js 和 Tailwind 创建的,它最终也像一行代码(但请注意它是如何跳跃的)。

我相信大家可以想象如何使用 Vue 和 React 等等以一种可以轻松维护文本区和其他元素之间状态的方式来做到这一点。 我不会在这里提供示例,部分原因是我懒惰,但主要是因为我认为您应该了解 *如何* 工作。 它会让您更聪明,更好地理解您的网站。