Chrome浏览器textarea字符达65k时出现无法移除横向滚动条问题咨询
成因说明
这是Chromium内核排版引擎Blink的已知历史遗留bug,触发逻辑如下:
Blink为了优化textarea的文本渲染性能,对文本宽度预计算设置了固定的缓冲区上限,当文本总字符数接近2^16(65536)的临界值时,内核的字符宽度累加计算会出现整数溢出,错误地将整段文本的总线性宽度判定为单行内容宽度,远大于textarea的实际可视宽度。
由于该宽度计算是内核渲染层面的硬逻辑,优先级高于CSS的overflow、white-space等属性配置,因此常规的CSS属性无法覆盖该错误计算结果,导致横向滚动条无法被移除。指定font-size、font-family属性会改变单个字符的宽度,因此不同字体下触发该bug的临界字符数会有小幅浮动,通常在6.3万到6.7万之间。Firefox浏览器的Gecko排版引擎没有该缓冲区设计,因此不会触发该问题。
解决方案
永久规避方案
优先使用设置了contenteditable="true"的div元素替代原生textarea,contenteditable元素的文本宽度计算逻辑不受该bug影响,同时可以实现和textarea一致的编辑效果。
业务兼容方案
如果必须使用原生textarea,可以提前对输入内容长度做限制,将最大输入字符数限制在6万以内,避免达到临界阈值;如果业务允许长文本输入,可将内容做分片加载处理,避免单textarea内一次性渲染过长文本。
临时修复方案
触发bug后可通过JS强制重排消除滚动条:先将textarea的value置空,再在下一个微任务周期将原值回填,触发内核重新计算排版。该方案会有极短的内容闪烁,仅适合非高频输入的场景使用。
临界时机检测方法
可以通过两个维度组合检测:
- 前置预警:监听textarea的input事件,当字符长度达到6万时触发预警逻辑,提前执行分片或提示操作
- 实时校验:对比textarea的
scrollWidth和clientWidth属性,当scrollWidth突然大幅超出clientWidth(排除设置了white-space: nowrap等会正常产生横向滚动的配置)时,说明已经触发该bug。
内容的提问来源于stack exchange,提问作者Kevin Danikowski

