配了五年 textarea,每次想让它自动增高都要写 30 行 JS——今天这件事被 CSS 一个属性彻底变了

每个项目里都有那么 10 行代码长得一模一样:监听 input 事件,把 height 设成 auto,读 scrollHeight,再设回去。功能正常,但每次新开一个表单你都要复制粘贴一遍,而且它有坑——textarea 隐藏时取值不准、字体异步加载后要手动重算、从 localStorage 恢复草稿时容易漏掉初始化调用。

2026 年,这 10 行可以删掉了。

field-sizing 是什么

field-sizing 是 CSS 新增的属性,最有用的值是 content。它让表单控件根据自己的内容计算尺寸,而不是死守 rows 属性或者固定宽高。

textarea {
  field-sizing: content;
  min-height: 3lh;
  max-height: 12lh;
}

三行,textarea 从固定高度变成自动增高——用户打字它就长,超过 12 行就滚动了,不再需要任何 JS。lh 是「当前元素一行的高度」,所以 min-height: 3lh 永远等于「3 行文字的高度」,换了字体大小它自动跟着变。

不只是 textarea。input、select 这些控件也能用:

/* inline-edit 场景,输入框宽度跟着内容走 */
.inline-edit {
  field-sizing: content;
  min-width: 6ch;
}

/* select 选择后自动缩到选项宽度 */
select {
  field-sizing: content;
}

浏览器支持:2026 年刚进 Baseline

这是关键信息——2026 年 6 月 Firefox 152 发布之后,field-sizing: content 才正式进入 Baseline 2026 行列。Chrome/Edge 从 123 开始支持(2024 年 3 月),Safari 从 26.2 开始,Firefox 152(2026 年 6 月)是最后一块拼图。全球覆盖率约 84%。

Baseline 2026 意味着:在最新版本的 Chrome、Firefox、Safari 三大引擎上行为一致,可以作为生产选项。剩下 16% 的访问会忽略这个属性,你的 textarea 退回到 rows 属性指定的固定高度——什么都不坏,只是没有自动增高。

如果你的产品用户群里老版本浏览器占比还比较高,用渐进增强保底:

textarea {
  min-height: 3rem; /* 基础降级高度 */
  resize: vertical;
}

@supports (field-sizing: content) {
  textarea {
    field-sizing: content;
    min-height: 3lh;
    max-height: 12lh;
    resize: none; /* 浏览器接管后不需要手动拉伸 */
  }
}

不支持 field-sizing 的浏览器会忽略 @supports 里的声明,手动拉伸仍然工作。支持的话 textarea 全自动,你不需要任何 JS。

scrollHeight 那套方案的三个坑

旧方案有三个天然缺陷:

字体加载后要重算。 你在页面顶部放了一个 textarea,草稿里有 3 行文字,首次渲染时用的是 fallback 字体(字体 A),JS 拿到的 scrollHeight 基于字体 A。字体 A 加载完成之后变成字体 B,行高变了,textarea 需要重新计算——但你的 JS 只在 input 事件里触发,字体切换时没有触发输入事件,所以 textarea 停留在错误的高度。field-sizing 是浏览器布局引擎的一部分,字体替换后自动重算。

隐藏元素取值不准。 如果 textarea 初始状态是 display: none 或者在 offscreen 的 tab 里,scrollHeight 返回的是 0,初始化时高度会算错。你需要等它可见之后再触发一次 resize 调用。field-sizing 不存在这个问题,因为它只在元素真正参与布局时才生效。

每次输入都强制布局重算。 JS 版本的 auto-resize 在每个字符输入时都读一次 scrollHeight,然后写一次 height。scrollHeight 的读取会强制浏览器同步计算布局,这是已知的性能陷阱——在输入事件里做同步 layout 是典型的 INP(Interaction to Next Paint)杀手。field-sizing 是声明式的,浏览器在下一帧渲染时统一处理,不会在每个字符输入时都触发一次同步布局计算。

三步迁移路径

  1. 找代码库里所有 textarea 相关的 scrollHeight 读取逻辑,用 field-sizing 替代。搜「scrollHeight」和「textarea」,每个命中都是一个可以删除的 JS 文件。

  2. 在 textarea 基础样式里加 @supports(field-sizing: content) 渐进增强包装,原来的 JS 降级代码只在 CSS.supports(‘field-sizing’, ‘content’) 返回 false 时才加载。

  3. 如果你的 textarea 有保存草稿功能(从 localStorage 恢复 value),确认旧 JS 初始化调用不再需要——field-sizing 在渲染时自动正确计算,不需要手动触发。

还有两个细节

宽度要约束,否则先横向长。 field-sizing: content 的 textarea 先在横向上增长,超过 max-width 限制后才开始增加高度。如果你要的是「只能竖向增长」,一定要设置 width 或 max-width。

rows 属性降级为 fallback。 在支持 field-sizing 的浏览器里,rows 属性对 textarea 高度不再起作用,它只是不支持时的降级方案。所以 rows=”3″ 仍然要写在 HTML 里,但作用是给老浏览器看的。

搜一下项目里有没有 textarea 相关的 auto-resize 代码,有的下午就可以删了。

评论区

0 条评论

登录后可评论。

阿柯·前端架构 75 阅读