如何创建行号始终与textarea行对齐的可滚动编辑器?
解决方案
你的问题核心在于行号容器的定位逻辑和滚动联动方式错误,导致新增行时行号反向偏移。以下是具体修复方案:
关键问题分析
.numbers使用position:sticky会固定在容器顶部,无法随内容滚动- 手动计算
top偏移的逻辑完全反向,正数偏移会让行号容器向下移动,而非向上 - 行号计数器未重置,会出现累加错误
- 滚动容器的 padding 布局导致行号与内容对齐错位
修改后的完整代码
CSS 调整
body { font-family: Consolas, "Courier New", Courier, monospace; } .editor { display: inline-flex; gap: 10px; font-family: Consolas, "Courier New", Courier, monospace; line-height: 21px; background: #282a3a; border-radius: 2px; padding: 0; overflow-y: auto; max-height: 250px; border-left: 10px solid #333; } .numbers { width: 20px; text-align: right; background: #333; padding: 20px 10px; counter-reset: linenumber; /* 重置行号计数器 */ } .numbers span { counter-increment: linenumber; } .numbers span::before { content: counter(linenumber); display: block; color: #506882; } textarea { line-height: 21px; overflow-y: hidden; padding: 20px 10px; border: 0; background: #282a3a; color: #fff; min-width: 500px; outline: none; resize: none; font-family: Consolas, "Courier New", Courier, monospace; flex: 1; }
JavaScript 修复
function updateRowNumbering(textarea) { const lines = textarea.value.split("\n"); const num = lines.length; const numbers = textarea.parentNode.querySelector(".numbers"); // 生成对应行数的行号节点 numbers.innerHTML = Array(num).fill("<span></span>").join(""); // 让行号容器高度与文本内容高度完全匹配,保证滚动同步 numbers.style.height = textarea.scrollHeight + "px"; }
HTML 优化(增强输入事件覆盖)
<div class="editor"> <div class="numbers"> <span></span> </div> <textarea id="textarea" rows="10" cols="50" oninput="updateRowNumbering(this)" onscroll="updateRowNumbering(this)"></textarea> </div>
修复要点说明
- 移除
.numbers的sticky定位,让它作为 Flex 布局的一部分,随滚动容器自然滚动,实现行号与内容同步移动 - 添加
counter-reset确保行号每次都从 1 开始计数,避免累加错误 - 将原容器的 padding 拆分到行号和文本框中,保证内容对齐
- 去掉手动计算
top偏移的错误逻辑,改为通过匹配文本框内容高度实现滚动同步 - 把
onkeyup改为oninput,覆盖粘贴、拖拽等非键盘输入场景
内容的提问来源于stack exchange,提问作者Abednego Nasila
相关产品推荐
相关产品推荐

