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

为何移除绝对定位DOM时父元素高度未变却触发scroll事件

移除absolute定位元素时意外触发scroll事件的原因与解决方案

问题场景

  1. 存在一个position: relative、高度5000px的父DOM;
  2. 子元素为position: absolute定位,高度小于父DOM;
  3. 移除其中的item1时会触发scroll事件,示例代码中item1在5秒后被移除,终端会打印scroll。

代码示例

JavaScript

const removeDom = () => {
  document.getElementById("remove").remove();
}

const container = document.getElementById("container");
container.addEventListener("scroll", () => {
  console.log("scroll")
})

container.scrollTop = 1000;
setTimeout(() => {
  removeDom();
}, 5000)

CSS

.item {
  height: 100px;
  width: 100%;
  border: 1px solid black;
}

HTML

<div id="container" style="height: 100vh; overflow: auto;">
  <div style="height: 5000px; position: relative;">
    <div style="position: absolute; top: 700px;">
      <div id="remove" class="item">item1</div>
      <div class="item">item2</div>
      <div class="item">item3</div>
      <div class="item">item4</div>
      <div class="item">item5</div>
      <div class="item">item6</div>
      <div class="item">item7</div>
      <div class="item">item8</div>
    </div>
  </div>
</div>

原因分析

这是浏览器的**滚动锚定(Scroll Anchoring)**机制在搞鬼:

  • 当设置container.scrollTop = 1000时,视口定位到容器内1000px的位置,此时item2及后续元素处于视口范围内;
  • 移除item1后,absolute定位的子容器高度减少100px,内部的item2及以下元素会自动向上偏移100px;
  • 浏览器为了避免用户正在看的内容突然跳走,会自动调整scrollTop的值来维持原视口的内容位置,这个调整操作就触发了scroll事件。

解决方案

1. 禁用滚动锚定(推荐)

给滚动容器添加overflow-anchor: none样式,直接阻止浏览器的自动scrollTop调整行为:

#container {
  overflow-anchor: none;
}

或者直接在HTML内联样式中添加:

<div id="container" style="height: 100vh; overflow: auto; overflow-anchor: none;">

2. 临时取消scroll监听再恢复

如果不想全局禁用滚动锚定,可以在移除元素前后暂时移除scroll事件监听,操作完成后再恢复:

const scrollHandler = () => {
  console.log("scroll")
}

const removeDom = () => {
  // 先移除监听
  container.removeEventListener("scroll", scrollHandler);
  document.getElementById("remove").remove();
  // 异步恢复监听,避免触发不必要的scroll
  setTimeout(() => {
    container.addEventListener("scroll", scrollHandler);
  }, 0);
}

const container = document.getElementById("container");
container.addEventListener("scroll", scrollHandler);

container.scrollTop = 1000;
setTimeout(() => {
  removeDom();
}, 5000)

3. 用隐藏替代移除(业务允许的话)

如果不需要完全删除DOM元素,只是隐藏,可以设置visibility: hidden或opacity: 0,这样元素占据的空间不变,不会触发布局偏移和滚动锚定:

const removeDom = () => {
  document.getElementById("remove").style.visibility = "hidden";
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 06:10:29