原生 JS 实现滚动导航吸顶:智能吸顶 + 高亮联动 + 平滑过渡(附完整源码)

一、功能背景与应用场景

滚动导航吸顶(Sticky Nav)是现代 Web 页面的核心交互组件,核心作用是固定导航栏,解决长页面滚动后导航消失、用户切换页面板块不便的问题。常见应用场景覆盖全行业:

  • 官网首页:顶部导航滚动后吸顶,方便用户快速切换板块
  • 电商商城:商品列表页 / 详情页,吸顶导航固定分类 / 筛选选项
  • 博客 / 文档:长文章页面,吸顶导航关联章节,支持快速跳转
  • 后台管理系统:顶部导航 + 侧边栏吸顶,提升操作效率

基础吸顶仅实现 "滚动到指定位置固定",本文实现的版本升级为企业级标准,解决生硬切换、无高亮联动、性能损耗等痛点,兼顾体验与性能。

二、核心实现效果

  1. 智能吸顶:滚动距离超过导航栏顶部阈值,自动吸顶;滚动回到顶部,自动取消吸顶,过渡平滑
  2. 高亮联动:滚动到对应页面板块,导航菜单自动高亮,实时匹配当前视图位置
  3. 平滑过渡:吸顶 / 取消吸顶添加 CSS 动画,避免生硬跳转,提升视觉体验
  4. 点击跳转:点击导航菜单,平滑滚动到对应板块,同时高亮当前菜单
  5. 性能优化:滚动监听节流、点击事件防抖,避免频繁 DOM 操作,降低性能损耗
  6. 响应式适配:PC 端显示完整导航,移动端折叠为汉堡菜单,吸顶功能同步适配
  7. 样式增强:吸顶后导航添加阴影、背景色变化,区分吸顶与非吸顶状态,提升视觉层级

三、完整可运行源码

html

预览

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原生JS实现滚动导航吸顶+高亮联动</title>
    <meta name="keywords" content="滚动吸顶,导航高亮,原生JS,平滑滚动,滚动监听,响应式导航">
    <meta name="description" content="原生JavaScript实现企业级滚动导航吸顶,支持智能吸顶、滚动高亮联动、平滑过渡、响应式适配,附完整源码和性能优化技巧。">
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 全局样式重置 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", sans-serif;
            text-decoration: none;
            list-style: none;
        }

        body {
            color: #333;
            line-height: 1.8;
            background-color: #f8f9fa;
        }

        /* 顶部banner(模拟页面顶部内容) */
        .banner {
            width: 100%;
            height: 300px;
            background: linear-gradient(135deg, #3498db, #2980b9);
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-size: 32px;
            font-weight: 500;
        }

        /* 导航栏基础样式 */
        .nav-container {
            width: 100%;
            background-color: #fff;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
            transition: all 0.3s ease;
            position: relative;
            z-index: 999;
        }

        /* 导航吸顶样式 */
        .nav-container.sticky {
            position: fixed;
            top: 0;
            left: 0;
            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
            background-color: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(5px); /* 毛玻璃效果,提升质感 */
        }

        .nav-content {
            max-width: 1200px;
            margin: 0 auto;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 20px;
        }

        .logo {
            font-size: 20px;
            font-weight: 600;
            color: #3498db;
            padding: 15px 0;
        }

        /* 导航菜单(PC端) */
        .nav-menu {
            display: flex;
            gap: 30px;
        }

        .nav-item a {
            display: block;
            padding: 20px 0;
            color: #666;
            font-size: 16px;
            transition: all 0.3s ease;
            position: relative;
        }

        /* 导航高亮样式 */
        .nav-item a.active {
            color: #3498db;
            font-weight: 500;
        }

        .nav-item a.active::after {
            content: "";
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 3px;
            background-color: #3498db;
            border-radius: 2px;
        }

        .nav-item a:hover {
            color: #3498db;
        }

        /* 汉堡菜单(移动端) */
        .menu-btn {
            display: none;
            font-size: 22px;
            color: #333;
            cursor: pointer;
            padding: 15px 0;
        }

        /* 页面内容区域 */
        .content {
            max-width: 1200px;
            margin: 50px auto;
            padding: 0 20px;
        }

        .section {
            margin-bottom: 80px;
            padding: 30px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
        }

        .section h2 {
            font-size: 24px;
            color: #2c3e50;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 1px solid #eee;
        }

        .section p {
            font-size: 16px;
            color: #666;
            margin-bottom: 15px;
            text-indent: 2em;
        }

        /* 响应式适配(移动端) */
        @media (max-width: 768px) {
            .banner {
                height: 200px;
                font-size: 24px;
            }

            .nav-menu {
                position: fixed;
                top: 65px;
                left: -100%;
                width: 100%;
                height: calc(100vh - 65px);
                background-color: #fff;
                flex-direction: column;
                gap: 0;
                transition: all 0.3s ease;
                padding: 20px;
                box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            }

            .nav-menu.active {
                left: 0;
            }

            .nav-item a {
                padding: 15px 0;
                border-bottom: 1px solid #eee;
            }

            .nav-item:last-child a {
                border-bottom: none;
            }

            .menu-btn {
                display: block;
            }

            .section {
                padding: 20px;
                margin-bottom: 50px;
            }

            .section h2 {
                font-size: 20px;
            }

            .section p {
                font-size: 14px;
            }
        }

        /* 平滑滚动全局设置 */
        html {
            scroll-behavior: smooth;
        }
    </style>
</head>
<body>
    <!-- 顶部Banner -->
    <div class="banner">滚动导航吸顶演示</div>

    <!-- 导航栏容器 -->
    <div class="nav-container" id="navContainer">
        <div class="nav-content">
            <div class="logo">导航吸顶Demo</div>
            <!-- 汉堡菜单(移动端) -->
            <div class="menu-btn" id="menuBtn">
                <i class="fas fa-bars"></i>
            </div>
            <!-- 导航菜单 -->
            <ul class="nav-menu" id="navMenu">
                <li class="nav-item">
                    <a href="#home" class="active" data-target="home">首页</a>
                </li>
                <li class="nav-item">
                    <a href="#about" data-target="about">关于我们</a>
                </li>
                <li class="nav-item">
                    <a href="#service" data-target="service">服务介绍</a>
                </li>
                <li class="nav-item">
                    <a href="#case" data-target="case">案例展示</a>
                </li>
                <li class="nav-item">
                    <a href="#contact" data-target="contact">联系我们</a>
                </li>
            </ul>
        </div>
    </div>

    <!-- 页面内容区域 -->
    <div class="content">
        <section class="section" id="home">
            <h2>首页</h2>
            <p>首页板块:滚动导航吸顶功能是现代Web页面的核心交互之一,能够提升用户在长页面中的操作体验。当页面滚动时,导航栏会自动固定在顶部,方便用户随时切换页面板块,无需手动滚动回到顶部寻找导航。</p>
            <p>本案例基于原生JavaScript开发,无任何第三方框架依赖,核心实现智能吸顶、滚动高亮联动、平滑过渡等功能,同时兼顾性能优化和响应式适配,可直接集成到各类Web项目中。</p>
            <p>首页作为页面的入口,通常包含页面核心主题和引导内容,滚动导航吸顶在此处的作用的是,当用户向下滚动浏览时,始终能看到导航菜单,快速跳转到其他板块,提升用户浏览效率。</p>
        </section>

        <section class="section" id="about">
            <h2>关于我们</h2>
            <p>关于我们板块:本团队专注于前端开发实战,致力于打造高质量、高可用的Web组件和项目解决方案。我们擅长原生JavaScript、HTML、CSS开发,同时精通Vue、React等主流前端框架,能够满足不同场景的开发需求。</p>
            <p>本次实现的滚动导航吸顶组件,是我们结合多年实战经验,优化后的企业级版本,解决了基础吸顶组件的生硬切换、无高亮联动、性能损耗等痛点,兼顾体验与性能,适合各类长页面使用。</p>
            <p>我们始终坚持"用户体验优先"的开发理念,每一个组件都经过多场景测试和优化,确保在不同浏览器、不同设备上都能流畅运行,同时提供完整的源码和注释,便于开发者学习和二次扩展。</p>
        </section>

        <section class="section" id="service">
            <h2>服务介绍</h2>
            <p>服务介绍板块:我们提供全方位的前端开发服务,涵盖Web组件开发、页面搭建、交互优化、响应式适配、性能优化等多个领域,助力企业快速打造高质量的Web产品。</p>
            <p>核心服务包括:原生JS组件开发(如导航吸顶、轮播图、手风琴等)、前端页面定制开发、移动端适配、单页应用(SPA)开发、前端性能优化、浏览器兼容性处理等。</p>
            <p>本次开发的滚动导航吸顶组件,是我们众多前端组件中的一个,后续还会推出更多实用的前端组件,涵盖交互、工具、动画等多个类别,满足开发者的各类需求,同时提供详细的实现教程和源码。</p>
        </section>

        <section class="section" id="case">
            <h2>案例展示</h2>
            <p>案例展示板块:以下是我们近期完成的部分前端项目案例,涵盖官网、电商、后台管理等多个领域,每一个案例都注重用户体验和性能优化,得到了客户的高度认可。</p>
            <p>案例1:企业官网开发,集成滚动导航吸顶、轮播图、手风琴等交互组件,适配PC/移动端,页面加载速度快,交互流畅,提升了企业品牌形象和用户浏览体验。</p>
            <p>案例2:电商商城页面开发,实现商品列表、详情页、购物车等核心功能,集成导航吸顶、筛选联动、平滑滚动等交互,优化页面加载性能,提升用户购物体验。</p>
            <p>案例3:后台管理系统开发,设计简洁高效的界面,集成顶部+侧边栏吸顶导航,实现数据展示、表单提交、权限控制等功能,提升管理员操作效率。</p>
        </section>

        <section class="section" id="contact">
            <h2>联系我们</h2>
            <p>联系我们板块:如果您有前端开发需求,或者对我们的组件有任何疑问、建议,欢迎随时联系我们,我们将第一时间为您提供专业的解决方案和技术支持。</p>
            <p>联系电话:123-4567-8910</p>
            <p>联系邮箱:demo@example.com</p>
            <p>地址:北京市朝阳区XX大厦XX层</p>
            <p>我们期待与您合作,共同打造高质量的Web产品,助力企业数字化转型。</p>
        </section>
    </div>

    <script>
        // 全局配置项(可根据需求自定义)
        const NAV_CONFIG = {
            stickyThreshold: 300,    // 吸顶触发的滚动距离阈值(px),对应banner高度
            throttleTime: 100,       // 滚动监听节流时间(ms)
            debounceTime: 200,       // 点击防抖时间(ms)
            activeOffset: 100        // 导航高亮的偏移量(px),避免因吸顶导航遮挡板块
        };

        // DOM元素缓存
        const navContainer = document.getElementById('navContainer');
        const navMenu = document.getElementById('navMenu');
        const menuBtn = document.getElementById('menuBtn');
        const navItems = document.querySelectorAll('.nav-item a');
        const sections = document.querySelectorAll('.section');

        // 初始化导航吸顶功能
        function initNavSticky() {
            // 绑定滚动监听(节流处理)
            window.addEventListener('scroll', throttle(handleScroll, NAV_CONFIG.throttleTime));
            
            // 绑定导航点击事件(防抖处理)
            navItems.forEach(item => {
                item.addEventListener('click', debounce(handleNavClick, NAV_CONFIG.debounceTime));
            });
            
            // 绑定移动端汉堡菜单点击事件
            menuBtn.addEventListener('click', toggleMobileMenu);
            
            // 初始检查吸顶状态和导航高亮
            checkStickyStatus();
            updateNavActive();
        }

        // 处理滚动事件:控制吸顶状态和导航高亮
        function handleScroll() {
            checkStickyStatus();
            updateNavActive();
        }

        // 检查并切换导航吸顶状态
        function checkStickyStatus() {
            // 获取当前滚动距离(兼容不同浏览器)
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            
            // 根据滚动距离切换吸顶状态
            if (scrollTop >= NAV_CONFIG.stickyThreshold) {
                navContainer.classList.add('sticky');
            } else {
                navContainer.classList.remove('sticky');
                // 移动端滚动回到顶部,关闭汉堡菜单
                if (navMenu.classList.contains('active')) {
                    navMenu.classList.remove('active');
                    menuBtn.innerHTML = '<i class="fas fa-bars"></i>';
                }
            }
        }

        // 更新导航高亮:匹配当前滚动到的板块
        function updateNavActive() {
            let currentSectionId = 'home'; // 默认高亮首页
            const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
            
            // 遍历所有板块,判断当前滚动位置对应的板块
            sections.forEach(section => {
                const sectionTop = section.offsetTop - NAV_CONFIG.activeOffset;
                const sectionHeight = section.offsetHeight;
                // 滚动位置在当前板块范围内,更新当前板块ID
                if (scrollTop >= sectionTop && scrollTop < sectionTop + sectionHeight) {
                    currentSectionId = section.id;
                }
            });
            
            // 切换导航高亮状态
            navItems.forEach(item => {
                if (item.dataset.target === currentSectionId) {
                    item.classList.add('active');
                } else {
                    item.classList.remove('active');
                }
            });
        }

        // 处理导航点击事件:平滑滚动到对应板块
        function handleNavClick(e) {
            e.preventDefault(); // 阻止默认锚点跳转
            
            const targetId = this.dataset.target;
            const targetSection = document.getElementById(targetId);
            if (!targetSection) return;
            
            // 计算目标板块的滚动位置(减去吸顶导航的高度,避免遮挡)
            const navHeight = navContainer.offsetHeight;
            const targetTop = targetSection.offsetTop - navHeight;
            
            // 平滑滚动到目标位置
            window.scrollTo({
                top: targetTop,
                behavior: 'smooth'
            });
            
            // 移动端点击后关闭汉堡菜单
            if (navMenu.classList.contains('active')) {
                navMenu.classList.remove('active');
                menuBtn.innerHTML = '<i class="fas fa-bars"></i>';
            }
        }

        // 切换移动端汉堡菜单
        function toggleMobileMenu() {
            navMenu.classList.toggle('active');
            // 切换汉堡菜单图标
            if (navMenu.classList.contains('active')) {
                menuBtn.innerHTML = '<i class="fas fa-times"></i>';
            } else {
                menuBtn.innerHTML = '<i class="fas fa-bars"></i>';
            }
        }

        // 节流函数:限制函数执行频率,优化性能
        function throttle(fn, delay) {
            let lastTime = 0;
            return function(...args) {
                const now = Date.now();
                if (now - lastTime >= delay) {
                    fn.apply(this, args);
                    lastTime = now;
                }
            };
        }

        // 防抖函数:避免快速多次触发,防止滚动/点击异常
        function debounce(fn, delay) {
            let timer = null;
            return function(...args) {
                clearTimeout(timer);
                timer = setTimeout(() => {
                    fn.apply(this, args);
                }, delay);
            };
        }

        // 扩展功能:对外暴露API
        window.NavSticky = {
            // 手动触发吸顶
            sticky: function() {
                navContainer.classList.add('sticky');
            },
            // 手动取消吸顶
            unSticky: function() {
                navContainer.classList.remove('sticky');
            },
            // 手动高亮指定导航项
            setActive: function(targetId) {
                navItems.forEach(item => {
                    if (item.dataset.target === targetId) {
                        item.classList.add('active');
                    } else {
                        item.classList.remove('active');
                    }
                });
            },
            // 更新配置
            updateConfig: function(newConfig) {
                Object.assign(NAV_CONFIG, newConfig);
            }
        };

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', initNavSticky);
    </script>
</body>
</html>

四、核心代码解析

1. 样式设计核心

  • 吸顶样式切换 :通过.sticky类控制导航栏position: fixed,结合transition实现平滑过渡,避免生硬切换
  • 视觉增强 :吸顶后添加阴影、毛玻璃效果(backdrop-filter: blur),区分吸顶与非吸顶状态,提升质感
  • 高亮样式 :通过.active类控制导航文字颜色,添加底部下划线,明确当前高亮项
  • 响应式适配:PC 端显示完整导航,移动端折叠为汉堡菜单,点击展开 / 收起,吸顶功能同步适配
  • 平滑滚动 :全局设置html { scroll-behavior: smooth; },配合 JS 控制滚动位置,实现点击跳转平滑过渡

2. JavaScript 核心逻辑

(1)智能吸顶实现

核心是监听scroll事件,判断滚动距离是否超过阈值(banner 高度),切换导航栏的sticky类:

  1. 兼容不同浏览器的滚动距离获取方式,避免兼容性问题
  2. 滚动超过阈值,添加.sticky类,导航固定在顶部;滚动回到顶部,移除类,恢复默认状态
  3. 移动端滚动回到顶部时,自动关闭汉堡菜单,提升体验
(2)滚动高亮联动

实时匹配当前滚动到的板块,自动高亮对应导航项,核心步骤:

  1. 遍历所有页面板块,计算每个板块的顶部位置和高度
  2. 根据当前滚动距离,判断用户当前视图所在的板块
  3. 切换导航项的.active类,实现高亮联动,默认高亮首页
(3)性能优化关键点
  • 滚动监听节流 :限制scroll事件处理函数的执行频率(默认 100ms),避免频繁触发,降低性能损耗
  • 点击事件防抖:防止快速多次点击导航,导致滚动异常
  • DOM 缓存:提前缓存所有需要操作的 DOM 元素,避免重复查询 DOM,减少重排重绘
  • 高效判断 :通过offsetTopoffsetHeight计算板块位置,逻辑简洁,执行高效
(4)移动端适配逻辑
  • 媒体查询隐藏 PC 端导航,显示汉堡菜单
  • 点击汉堡菜单,切换导航菜单的active类,实现展开 / 收起
  • 导航点击后,自动关闭汉堡菜单,提升移动端操作体验

3. 模块化与扩展性设计

  • 配置化 :通过NAV_CONFIG集中管理吸顶阈值、节流防抖时间、高亮偏移量等参数,便于自定义
  • 函数拆分:将初始化、滚动处理、吸顶判断、高亮更新、移动端菜单切换等逻辑拆分为独立函数,便于维护
  • 对外 API :暴露sticky/unSticky/setActive/updateConfig方法,支持外部手动控制面板状态,增强扩展性

五、扩展与定制方向

  1. 功能扩展

    • 添加导航滚动动画:吸顶 / 取消吸顶时,添加导航栏高度变化动画,提升视觉效果
    • 导航搜索框:吸顶后显示搜索框,非吸顶时隐藏,节省页面空间
    • 滚动进度显示:在导航栏添加滚动进度条,实时显示页面滚动进度
    • 多级导航:支持二级导航,吸顶后二级导航展开 / 收起,适配复杂导航场景
    • 记忆导航状态:结合localStorage记忆用户上次点击的导航项,页面刷新后保持高亮
  2. 样式定制

    • 主题色自定义:通过 CSS 变量统一管理导航颜色、高亮色、背景色,一键切换主题
    • 吸顶样式定制:支持自定义吸顶后的阴影、透明度、毛玻璃效果
    • 导航布局定制:支持左侧导航、顶部导航、双侧导航等多种布局
    • 高亮样式定制:支持下划线、背景色、文字放大等多种高亮效果
  3. 业务集成

    • 结合路由:在单页应用(SPA)中,根据路由自动高亮对应导航项
    • 埋点统计:添加导航点击、吸顶触发等埋点,统计用户行为
    • 权限控制:根据用户权限,显示 / 隐藏对应的导航项
    • 懒加载结合:滚动到指定板块后,再渲染板块内容,提升首屏加载速度

六、总结

本文实现的滚动导航吸顶组件,突破了基础吸顶的功能局限,整合了智能吸顶、滚动高亮联动、平滑过渡、响应式适配等企业级特性,兼顾用户体验与性能。代码模块化程度高、注释完整,既适合前端初学者学习滚动监听、节流防抖、DOM 操作等核心知识点,也可直接集成到官网、商城、后台管理等各类长页面。

组件的配置化设计和对外 API,降低了二次开发成本,开发者可根据业务需求快速定制样式和功能,适配不同的应用场景。同时,本文补充的性能优化和兼容性处理技巧,能够帮助开发者规避常见坑点,打造更稳定、更流畅的交互体验,是前端开发中极具实用价值的经典实战案例。

相关推荐
叫我一声阿雷吧2 天前
原生 JS 实现无限滚动加载(下拉加载更多 + 无闪烁 + 性能优化),长列表必备组件
无限滚动·节流·原生javascript·下拉加载更多·滚动监听·长列表优化·前端性能
叫我一声阿雷吧15 天前
原生 JS 实现图片预览上传组件:多图上传 + 拖拽上传 + 裁剪预览 + 进度显示(附完整源码)
图片上传·canvas·文件上传·响应式布局·拖拽上传·原生javascript·filereader api
RFCEO1 个月前
前端进阶 课程三十、CSS过渡、动画与交互效果(提升用户体验)
前端编程·css交互核心能力·基础变形·平滑过渡·复杂动画·日常ui开发需求·css3 html5
哈哈~haha4 个月前
ui5_Walkthrough_Step 34: Responsiveness响应式布局
响应式布局·responsiveness
白鹿第一帅5 个月前
DevUI 主题定制实战:CSS 变量实现品牌主题与暗黑模式开发指南
白鹿第一帅·响应式布局·css变量主题定制·暗黑模式开发·品牌主题设计·动态主题切换·前端视觉系统
西洼工作室5 个月前
CSS响应式布局全攻略
前端·css·响应式布局·栅格系统
停止重构10 个月前
【方案】前端UI布局的绝技,响应式布局,多端适配
前端·网页布局·响应式布局·grid布局·网页适配多端
三天不学习1 年前
CSS 之 响应式设计 前世今生
前端·css·响应式设计·响应式布局
三天不学习1 年前
前端开发之 节流与防抖
前端·javascript·节流防抖