用 scrollHeight 实现 textarea 高度自适应最稳定:每次 input 前先设 style.height = 'auto',再读取并设置 scrollHeight;需处理 IE11 换行符偏差和 iOS Safari 延迟问题。

textarea 高度随内容自动撑开但不滚动?用 scrollHeight 最稳
直接监听 input 事件,读取 textarea.scrollHeight,再赋给 style.height,就能让高度跟着文字变。别用 offsetHeight 或 clientHeight —— 它们不包含溢出部分,撑不开。
常见错误是设了 height: auto 就以为完事,其实默认行为是固定高度+滚动条;或者用 rows 属性硬调,结果换字体/缩放就错位。
-
scrollHeight是元素内部所有内容(包括不可见部分)的总高度,真实反映“需要多高才不滚动” - 记得先清除
style.height再读scrollHeight,否则旧高度会干扰计算 - 移动端 iOS Safari 对
scrollHeight更新有延迟,加个setTimeout(..., 0)能绕过
防抖 + 强制重置高度避免抖动
用户狂敲键盘时频繁改 style.height,会导致光标跳、渲染卡顿。关键不是“少触发”,而是“每次改前先归零”。
典型表现:输到一半突然跳行、回删时高度没及时缩回去、粘贴大段文本后留白太多。
立即学习“前端免费学习笔记(深入)”;
- 每次
input触发前,先设textarea.style.height = 'auto' - 再读
scrollHeight,然后设textarea.style.height = textarea.scrollHeight + 'px' - 用
requestAnimationFrame包一层比setTimeout更准,尤其在高刷屏上
兼容性坑:IE11 的 scrollHeight 偏差和换行符处理
IE11 下 scrollHeight 在空行或纯空格末尾时偏小,导致最后一行被截。根本原因是它把 \r\n 当一个字符算,而现代浏览器按 \n 归一化。
不用专门 polyfill,两行代码就能修:
textarea.value = textarea.value.replace(/\r\n/g, '\n');
再执行高度重设逻辑即可。另外 IE11 不支持 resize: none 关闭拖拽,得用 CSS 强制禁用:
textarea { resize: none; }
- Mac 上用户习惯用
Cmd+Enter换行,实际插入的是\n;Windows 是\r\n;IE11 对后者计算不准 - 如果后端要求保留原始换行符,那就不能 replace,得改用
textarea.scrollHeight + 2这种经验补偿(仅限 IE11)
要不要用 contenteditable 替代 textarea?
除非你要富文本、@ 提及、语法高亮这类功能,否则别碰。它带来一堆新问题:光标定位不准、剪贴板行为不一致、iOS 键盘收起后光标消失、getSelection() 在 iframe 里失效……
纯多行输入场景下,textarea 是唯一靠谱选择。所谓“更灵活”其实是把复杂度甩给了你。
-
contenteditable的scrollHeight计算更不稳定,尤其嵌套<br>时 - 无障碍支持差,读屏软件对它的语义识别远不如
textarea - 想加字数限制?
textarea用maxlength一行搞定;contenteditable得自己过滤input、paste、drop所有入口
高度自适应这事,核心就三步:清高 → 读高 → 设高。中间任何一步漏掉,都会在某个浏览器、某次粘贴、某个字号下露馅。











