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

如何让div的scrollTop值与textarea保持同步?

问题:textarea与同尺寸镜像div无法同步scrollTop值

我用一个div来格式化并显示textarea中的文本,要求二者始终保持同步,但当输入文本超出textarea底部后,无法同步它们的scrollTop值。我的实现思路参考了代码高亮编辑框的方案,但该方案在项目中不生效。


关键代码片段

HTML

<section>
  <div class="input-text__container">
    <div id="input-text--mirror" class="input-text"></div>
      <textarea
        id="input-text--original"
        cols="30"
        rows="6"
        autofocus
        class="input-text"
        placeholder="Enter your text here"
        autocomplete="off"
        autocorrect="off"
        spellcheck="false"
      ></textarea>
  </div>
<section>

CSS

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap');

html {
  font-size: 62.5%;
  box-sizing: border-box;
  scroll-behavior: smooth;
}

*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  border: 0;
  box-sizing: inherit;
  vertical-align: baseline;
}

body {
  height: 100vh;
}

section {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding: 1rem;
}

.input-text__container {
  width: 100%;
  position: relative;
  flex: 1;
}

.input-text {
  width: 100%;
  height: 100%;
  position: absolute;
  font-size: 3.2rem;
  overflow-wrap: break-word;
  font-family: "Inter";
}

#input-text--mirror {
  background-color: #e9ecf8;
  color: #0a3871;
  overflow: hidden;
}

#input-text--original {
  background-color: transparent;
  -webkit-text-fill-color: transparent;
  resize: none;
  outline: none;
  -ms-overflow-style: none; /* IE and Edge */
  scrollbar-width: none; /* Firefox */
}

#input-text--original::placeholder {
  color: #e9ecf8;
  -webkit-text-fill-color: #052051;
}

#input-text--original::selection {
  -webkit-text-fill-color: #ffffff;
}

.invalid {
  font-weight: 400;
  color: #ff0000;
}

#input-text--original::-webkit-scrollbar {
  display: none;
}

JavaScript

let invalidInput = false;
const patterns = {
  valid: "a-z ",
  invalid: "[^a-z ]",
  linebreaks: "\r|\r\n|\n",
};
const textIn = document.querySelector("#input-text--original");
const mirror = document.querySelector("#input-text--mirror");

function validateInput(string, className) {
  let anyInvalidChar = false;

  // Generate regular expressions for validation
  const regExpInvalids = new RegExp(patterns.invalid, "g");
  const regExpLinebreaks = new RegExp(patterns.linebreaks);

  // Generate innerHTML for mirror
  const mirrorContent = string.replace(regExpInvalids, (match) => {
    if (regExpLinebreaks.test(match)) {
      return "<br/>";
    } else {
      anyInvalidChar = true;
      return `<span class=${className}>${match}</span>`;
    }
  });
  // Update mirror
  mirror.innerHTML = mirrorContent;

  return anyInvalidChar;
}

textIn.addEventListener("input", (e) => {
  const plain = textIn.value;
  const newInputValidity = validateInput(plain, "invalid");
  mirror.scrollTop = textIn.scrollTop;
});

textIn.addEventListener(
  "scroll",
  () => {
    mirror.scrollTop = textIn.scrollTop;
  },
  { passive: true }
);

复现步骤

在桌面端输入前8个自然数并按列排列,即可复现scrollTop不同步的问题。


已尝试的无效方案

  • 将换行符替换为<br/>&nbsp;
  • 当最后一个字符是换行符时追加空格
  • 给mirror div添加overflow: scroll样式
  • 尝试使用offsetTop、pageYOffset等相关属性

需要不依赖任何框架/库的原生JavaScript解决方案。


内容的提问来源于stack exchange,提问作者Ayxa Chaverra Renteria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:50:29