textarea 高度自适应唯一可靠方案是动态设置 style.height = scrollheight + 'px',需先清空 height、读取 scrollheight、配合 min/max-height 等 css 属性,并注意 line-height 一致性与移动端 requestanimationframe。

rows 属性本身不能让 textarea 高度随内容自适应——它只是个语义提示值,不是高度控制手段。强行靠改 rows 实现自适应,会出错、卡顿、丢失滚动位置,且在 React/Vue 中极易引发重排问题。
为什么直接改 rows 不可靠
浏览器把 rows 当作“初始可见行数”来渲染,不响应内容变化;用户缩放页面、换字体、调字号后,rows="5" 可能只显示 2 行或撑出滚动条;JS 赋值 textarea.rows = 8 会被已有的 style.height 覆盖,甚至在 flex 容器里完全失效。
- 常见错误现象:
rows设成 1 后手动算scrollHeight / baseHeight,但没处理换行符差异(\r\n在 IE11 和现代浏览器中计算结果不同) - React 中绑定
rows属性,每次输入都触发 re-render + 重排,光标跳到开头 - 设了
min-height但忘了box-sizing: border-box,padding 把实际内容区挤窄了
scrollHeight 动态设 style.height 是唯一靠谱方案
必须先清空旧高度再读取,否则 iOS Safari 和 IE11 会缓存错误值,删文字后高度卡住不缩、粘贴后底部留白。
- 每轮调整前必须写:
textarea.style.height = 'auto' - 紧接着读:
textarea.scrollHeight(不是offsetHeight或clientHeight) - 赋值:
textarea.style.height = textarea.scrollHeight + 'px' - 移动端要包一层
requestAnimationFrame,避免 120Hz 屏上计算偏移
必须配合的 CSS 才算完整
纯 JS 算高度不管用,min-height 和 max-height 必须走 CSS,否则空 textarea 塌成一条线,或狂输时无限拉伸。
-
min-height: 80px—— 保证初始有可点击区域 -
max-height: 300px—— 超出后才出现滚动条 -
overflow-y: auto—— 不加这句,超限时内容被裁切 -
resize: none—— 防止用户拖拽破坏自适应逻辑 -
box-sizing: border-box—— 确保 padding/border 不额外增加高度
最容易被忽略的是样式与 JS 计算脱节:比如 JS 计算时用的是默认 line-height: normal,但 CSS 里写了 line-height: 1.5,结果高度偏差肉眼可见。真实高度必须以 computed style 为准,别信开发者工具里“user agent stylesheet”的默认值。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











