You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

textarea与后置高亮div同步自适应宽高异常问题排查

问题分析与修复方案

你的核心问题出在直接用后方div的scrollHeight设置textarea高度,以及缺少必要的样式对齐和防抖处理,导致高度计算偏差和卡顿。

问题1:高度计算偏差

textarea和后方div的盒模型默认存在差异(比如textarea自带默认border、padding,浏览器也可能有默认样式),直接拿ColoredEd.scrollHeight赋值给textarea,会导致高度叠加。另外,你没有先重置textarea的高度为auto,每次计算的scrollHeight都是基于上一次的错误高度,越算越大。

问题2:卡顿

每次输入都触发auto_grow,频繁修改样式会导致浏览器频繁重绘重排,引发卡顿。


修复步骤

1. 统一两个元素的盒模型样式

确保#main-code和#color-code的border、padding、box-sizing完全一致,避免布局差异:

#color-code, #main-code {
  padding: 16px;
  top: 0; left: 0; right: 0; bottom: 0;
  white-space: pre-wrap;
  font-family: monospace;
  font-size: 16px;
  line-height: inherit;
  border: none; /* 统一border */
  box-sizing: border-box; /* 让padding包含在宽高内 */
}

2. 修正高度计算逻辑

先把textarea的高度重置为auto,再获取真实的内容高度,避免历史高度干扰:

function auto_grow() {
  // 先重置高度,获取真实内容高度
  Editor.style.height = 'auto';
  // 用textarea自身的scrollHeight,而非后方div的
  const correctHeight = Editor.scrollHeight;
  Editor.style.height = correctHeight + 'px';
  
  // 宽度同理,先重置再计算
  Editor.style.width = 'auto';
  const correctWidth = Editor.scrollWidth;
  Editor.style.width = correctWidth + 'px';
}

为什么不用div的scrollHeight?因为textarea的内容和div是同步的,直接用自身的scrollHeight更准确,避免div的样式意外影响。

3. 添加防抖处理解决卡顿

用防抖函数限制auto_grow的调用频率,比如每100ms只执行一次:

// 防抖函数
function debounce(func, delay = 100) {
  let timeoutId;
  return function() {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, arguments), delay);
  };
}

// 绑定防抖后的函数
const debouncedAutoGrow = debounce(auto_grow);
// 给textarea绑定事件时用这个防抖函数
document.getElementById('main-code').addEventListener('input', debouncedAutoGrow);

4. 移除不必要的margin

你的textarea设置了margin-bottom:20px,这会导致容器高度额外增加,建议移除:

#main-code {
  position: relative;
  color: transparent;
  caret-color: hsl(50, 75%, 70%);
  /* margin-bottom: 20px; 移除这行 */
}

完整修正后的代码示例

HTML

<div class="my-code">
    <div id='color-code'></div>
    <textarea id='main-code'></textarea>
</div>

CSS

.my-code {
  position: relative;
  background: hsl(220, 16%, 14%);
  width: 80%;
  overflow: auto;
}

#color-code, #main-code {
  padding: 16px;
  top: 0; left: 0; right: 0; bottom: 0;
  white-space: pre-wrap;
  font-family: monospace;
  font-size: 16px;
  line-height: inherit;
  border: none;
  box-sizing: border-box;
}

#main-code {
  position: relative;
  color: transparent;
  caret-color: hsl(50, 75%, 70%);
  background: transparent; /* 确保背景完全透明 */
}

#main-code:focus {
  outline: 1px solid hsl(220, 16%, 19%);
}

#main-code::selection {
  background: hsla(0, 0%, 90%, 0.2);
}

#color-code {
  position: absolute;
  user-select: none;
}

JavaScript

const Editor = document.getElementById('main-code');
const ColoredEd = document.getElementById('color-code');

// 同步内容到高亮div(补充你原本的语法高亮逻辑)
Editor.addEventListener('input', () => {
  // 替换为你的语法高亮处理逻辑,这里用textContent做示例
  ColoredEd.textContent = Editor.value;
});

function auto_grow() {
  // 重置高度获取真实值
  Editor.style.height = 'auto';
  Editor.style.height = Editor.scrollHeight + 'px';
  
  // 重置宽度获取真实值
  Editor.style.width = 'auto';
  Editor.style.width = Editor.scrollWidth + 'px';
}

// 防抖处理
function debounce(func, delay = 100) {
  let timeoutId;
  return function() {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, arguments), delay);
  };
}

// 绑定事件
const debouncedAutoGrow = debounce(auto_grow);
Editor.addEventListener('input', debouncedAutoGrow);
// 初始化时执行一次
auto_grow();

内容的提问来源于stack exchange,提问作者ChessAndCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:15:43