滚动时固定右侧菜单底部并实现标签内容滚动
我来帮你搞定这个需求!你要实现的是滚动时右侧菜单固定,固定状态下标签内容能滚动且底部对齐视窗,当页面滚到足够底部时菜单底部对齐父容器。下面是调整后的完整代码和详细解释:
解决方案
核心思路拆解
- 第一步:监听页面滚动,判断菜单何时需要从默认状态切换到固定状态。
- 第二步:菜单固定时,动态计算标签内容区域的高度,让它刚好填满导航栏下方到视窗底部的空间,实现内容滚动。
- 第三步:当页面滚动到菜单底部即将碰到父容器底部时,切换菜单的固定方式,让它贴在父容器底部,避免遮挡下方的按钮。
修改后的JavaScript代码
window.addEventListener("scroll", handleScroll); function handleScroll() { const $panel = $(".menu")[0]; const $navbar = $(".navbar"); const navbarHeight = $navbar.outerHeight(); const windowHeight = $(window).height(); const $wrapper = $("#wrapper"); const wrapperOffsetTop = $wrapper.offset().top; const wrapperTotalHeight = $wrapper.outerHeight(); const wrapperBottom = wrapperOffsetTop + wrapperTotalHeight; const panelTotalHeight = $panel.offsetHeight; const tabNavHeight = $panel.querySelector(".nav-tabs").offsetHeight; // 菜单触发固定的滚动阈值(导航栏底部刚好碰到菜单顶部时的滚动距离) const stickThreshold = wrapperOffsetTop - navbarHeight; // 菜单触发底部对齐父容器的阈值(视窗顶部滚动到父容器底部上方一个视窗高度时) const bottomStickThreshold = wrapperBottom - windowHeight; if ($(this).scrollTop() > stickThreshold) { $panel.classList.add("sticky"); // 判断是否需要切换到父容器底部对齐模式 if ($(this).scrollTop() > bottomStickThreshold) { $panel.classList.add("sticky-bottom"); // 滚动区域高度 = 菜单总高度 - 标签栏高度 $panel.querySelector(".tab-content").style.height = `${panelTotalHeight - tabNavHeight}px`; } else { $panel.classList.remove("sticky-bottom"); // 滚动区域高度 = 视窗高度 - 导航栏高度 - 标签栏高度 $panel.querySelector(".tab-content").style.height = `${windowHeight - navbarHeight - tabNavHeight}px`; } } else { // 恢复默认状态 $panel.classList.remove("sticky"); $panel.classList.remove("sticky-bottom"); $panel.querySelector(".tab-content").style.height = ""; } }
调整后的CSS代码
.navbar { background-color: #fff; border-bottom: 1px solid; font-size: 48px; line-height: 48px; position: fixed; top: 0; left: 0; right: 0; z-index: 100; /* 确保导航栏在最上层 */ } .contents { margin-top: 55px; /* 给固定导航栏留出空间 */ } /* 菜单固定在视窗顶部时的样式 */ .menu.sticky { position: fixed; top: 55px; right: 0; width: 31.491712707182323%; z-index: 90; /* 低于导航栏,高于内容 */ } /* 菜单固定在父容器底部时的样式 */ .menu.sticky.sticky-bottom { top: auto; /* 取消顶部固定 */ bottom: 0; /* 固定在视窗底部,同时受父容器限制 */ } .menu .tab-content { padding: 20px; overflow-y: auto; /* 开启垂直滚动 */ /* 默认不设置高度,由JS动态计算 */ } .menu button { margin-top: 20px; } .btn.pull-right { margin: 20px; } /* 给父容器设置相对定位,确保菜单底部对齐时的参考正确 */ #wrapper { position: relative; }
完整HTML结构(需引入Bootstrap)
因为用到了nav-tabs和tab-pane的切换功能,需要引入Bootstrap的样式和脚本:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> <div class="navbar navbar-fixed-top">NAVBAR</div> <div class="contents"> <div class="row-fluid"> <div class="span12"> <h3>Here is some additional stuff</h3> <h5>And even more</h5> </div> </div> <div class="row-fluid"> <div id="wrapper"> <div class="span8" style="border: 1px solid blue;"> <p>Some content</p> <p>Some content</p> <p>Some content</p> <!-- 此处省略重复的内容p标签 --> </div> <div class="span4" style="border: 1px solid red;"> <div class="menu" style="border: 1px solid green;"> <ul class="nav nav-tabs"> <li><a href="#first" data-toggle="tab">First</a></li> <li><a href="#second" data-toggle="tab">Second</a></li> </ul> <div class="tab-content"> <div id="first" class="tab-pane active"> <ul> <li>Item</li> <li>Item</li> <!-- 此处省略重复的列表项li标签 --> </ul> </div> <div id="second" class="tab-pane">Second tab contents</div> </div> </div> </div> </div> </div> <div class="row-fluid"> <div class="span12"> <button class="btn pull-right">Button I don't want hidden</button> </div> </div> </div>
关键细节说明
- 动态高度计算:通过JS实时获取视窗、导航栏、标签栏的高度,确保滚动区域刚好填满可用空间,不会出现滚动条过长或过短的问题。
- 双固定模式切换:通过两个滚动阈值,分别控制菜单“顶部固定”和“底部对齐父容器”的切换,避免菜单遮挡页面底部的按钮。
- 层级管理:给导航栏和菜单设置不同的
z-index,确保导航栏始终在最上层,菜单在内容之上,避免被遮挡。
内容的提问来源于stack exchange,提问作者mellis481
相关产品推荐
相关产品推荐

