前端 技术随笔

JavaScript 滚动导航 + 吸顶方案:position sticky 与 scroll 监听

“滚动导航 + 吸顶”是常见交互:页面滚动到某个区域时,导航栏吸在顶部;点击导航还能跳到对应内容区并高亮当前项。下面给出基于 position: sticky 的方案,并补充传统 scroll 监听的兜底。

一、HTML 结构

<div class="right-section">
  <div class="nav-bar-wrap">
    <ul class="nav-bar">
      <li data-content="content1" class="active">导航1</li>
      <li data-content="content2">导航2</li>
      <li data-content="content3">导航3</li>
    </ul>
  </div>
  <div class="content content1">内容1</div>
  <div class="content content2">内容2</div>
  <div class="content content3">内容3</div>
</div>

二、吸顶:position: sticky

.nav-bar-wrap { height: 55px; }   /* 占位,避免吸顶后内容跳动 */
.nav-bar {
  position: sticky;
  top: 0;
}

关键注意:sticky 的任意祖先元素如果设置了 overflow: hidden / auto / scroll,吸顶会失效。所以让导航栏的滚动发生在 body 上,祖先不要加 overflow 限制。

三、滚动导航高亮(scroll 监听兜底)

var navs = document.querySelectorAll(".nav-bar li");
var contents = document.querySelectorAll(".content");

window.addEventListener("scroll", function () {
  var scrollTop = window.pageYOffset;
  contents.forEach(function (el, i) {
    if (el.offsetTop - 60 <= scrollTop) {
      navs.forEach(function (n) { n.classList.remove("active"); });
      navs[i].classList.add("active");
    }
  });
});

navs.forEach(function (nav) {
  nav.addEventListener("click", function () {
    var target = document.querySelector("." + nav.dataset.content);
    window.scrollTo({ top: target.offsetTop - 60, behavior: "smooth" });
  });
});

四、为什么用 sticky 而不是 fixed

  • fixed 脱离文档流,需要额外占位元素,否则内容会瞬间上移。
  • sticky 仍在文档流中,到达阈值才“吸住”,无需手动占位计算,体验更顺滑。
  • 对不支持 sticky 的旧浏览器,再用上面的 scroll 监听 + fixed 兼容。
标签
JavaScript前端交互