前端
技术随笔
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 兼容。