Bootstrap 5结合vanilla JS实现滚动时第二个导航栏吸顶固定
主导航栏滚动吸顶的纯JS实现方案
核心实现逻辑无冗余依赖,直接覆盖双导航结构的常见场景,同时规避布局跳动、滚动卡顿、状态失效等常见问题:
- 提前计算主导航栏相对于文档顶部的原始偏移位置,不在滚动过程中重复读取易变动的定位值
- 监听页面滚动行为,当垂直滚动距离达到导航原始偏移值时,给导航添加固定定位类实现视口顶部吸附
- 补偿固定定位带来的文档流高度差,避免导航吸顶瞬间下方内容跳动
- 对高频触发的滚动事件做节流处理,降低性能消耗
参考结构适配
对应双导航的页面结构,DOM布局逻辑如下:
<!-- 第一导航:顶部联系信息栏 --> <div class="contact-bar"> <span>服务热线:400-xxx</span> </div> <!-- 第二导航:需要实现吸顶的主导航栏 --> <nav class="main-nav"> <a href="/">首页</a> <a href="/product">产品</a> <a href="/contact">联系我们</a> </nav> <!-- 页面主体内容 --> <main class="page-content"> <!-- 页面正文内容 --> </main>
基础样式配置
* { margin: 0; padding: 0; box-sizing: border-box; } .contact-bar { height: 40px; background: #f0f2f5; } .main-nav { height: 60px; background: #ffffff; transition: top 0.2s ease; } /* 吸顶状态样式 */ .main-nav.nav-fixed { position: fixed; top: 0; left: 0; width: 100%; z-index: 999; } .page-content { padding-top: 24px; } /* 吸顶时的内容高度补偿,抵消导航脱离文档流的高度差 */ .page-content.content-fixed { padding-top: calc(24px + 60px); }
纯JS交互实现
// 缓存DOM元素 const mainNav = document.querySelector('.main-nav'); const pageContent = document.querySelector('.page-content'); // 存储主导航的原始顶部偏移值,初始加载时计算 let navOffsetTop = mainNav.offsetTop; let scrollTimer = null; // 吸顶状态判断逻辑 function updateNavStickyState() { // 获取当前页面垂直滚动距离 const currentScrollY = window.scrollY || document.documentElement.scrollTop; if (currentScrollY >= navOffsetTop) { mainNav.classList.add('nav-fixed'); pageContent.classList.add('content-fixed'); } else { mainNav.classList.remove('nav-fixed'); pageContent.classList.remove('content-fixed'); } } // 绑定滚动事件,加10ms节流避免高频计算卡顿 window.addEventListener('scroll', () => { if (scrollTimer) clearTimeout(scrollTimer); scrollTimer = setTimeout(updateNavStickyState, 10); }); // 页面加载完成时主动执行一次判断,处理刷新时已经处于吸顶位置的场景 window.addEventListener('load', updateNavStickyState); // 窗口尺寸变化时重新计算导航偏移值,适配响应式布局下的高度变化 window.addEventListener('resize', () => { // 先移除固定定位状态再计算原始偏移,避免被fixed定位干扰计算结果 mainNav.classList.remove('nav-fixed'); pageContent.classList.remove('content-fixed'); navOffsetTop = mainNav.offsetTop; updateNavStickyState(); });
注意事项
- 不要在滚动事件内实时读取导航的
offsetTop值:导航变为固定定位后,自身的offsetTop会变为0,会导致吸顶触发逻辑完全失效 - 如果不需要兼容IE等老旧浏览器,直接给主导航元素设置
position: sticky; top: 0;即可实现同等效果,无需额外JS,性能更优。注意sticky定位会受父元素overflow: hidden属性影响导致失效,使用时需排除这类干扰 - 必须处理固定定位带来的文档流高度差,否则导航吸顶瞬间下方内容会向上跳动一个导航的高度,影响视觉体验
内容的提问来源于stack exchange,提问作者jhon-jhones
相关产品推荐
相关产品推荐

