简介:面向需要用Bootstrap 3快速搭建后台布局或理解侧边导航栏用法的开发者,这份示例资源集中展示了侧边栏从结构到交互的完整实现方式。包内含一个可直接运行的HTML示例,配合Bootstrap的核心CSS与JavaScript文件以及jQuery库,清晰演示了如何构建导航列表、设置深色背景、利用响应式折叠类在小屏幕上收起菜单,并通过按钮控制展开与收拢。示例中还以可选状态样式提示当前选中链接,便于增强导航的视觉反馈;同时附带一组图标字体,可直接在菜单项中嵌入图标,免去另行寻找图标的麻烦。整个压缩包共9个文件,涵盖HTML页面、JS脚本、CSS样式及多种格式字体,体积仅170KB,轻量易部署。资源已有5177人浏览学习,适合前端入门者根据示例代码动手修改颜色、宽度与字体,也可作为项目脚手架,在此基础上添加子菜单、滚动监听等功能,显著减少从零搭建的时间。 接手了一个三年前上线的老后台项目,技术栈还稳稳停在 Bootstrap 3 上。需求方提了个常见要求:所有二级页面都要加一个左侧导航栏,用来在同一板块下切换不同功能页。这个功能听起来简单,真做起来才发现细节不少——折叠子菜单、当前高亮、滚动跟随、小屏适配、跟旧插件的冲突,每一样都能让你在下班前怀疑人生。
这篇文章我就把整个落地过程拆开来讲,从布局设计、代码实现到踩坑排查,完整还原一个 Bootstrap 3 侧边导航栏是怎么从零做出来并稳定跑在生产环境里的。如果你是第一次在 Bootstrap 3 项目里加侧边导航,或者正被手头的遗留系统折腾得头疼,这篇应该能帮你省掉大半天的试错时间。
1. 为什么老项目里的侧边导航栏,反而值得认真做
1.1 这不是"加个菜单"那么简单
Bootstrap 3 在 2024 年已经是一个非常老旧的版本,官方早就不维护了。但现实是,大量 2015 到 2018 年间上线的后台管理系统、CMS 站点仍然在用它,而且短期内没有任何升级计划。原因很现实:升级到 Bootstrap 4/5 意味着整套布局、栅格类名、JavaScript 插件行为全要适配,对业务系统来说风险远大于收益。
所以在这种老项目里加侧边导航栏,不是"改个模板"的小事,而是要在一个已经跑了好几年的系统里插入一套新的导航体系。你面对的往往是各种自定义 CSS、重复的页面头尾、好几套不同风格的菜单,稍不留神就会让整站风格出现割裂感。
我接手时的过时页面状态是这样:顶部导航栏已经塞了二十多个入口,二级页面全靠页面内的手写跳转链接,用户经常找不到同样板块下的其他功能。这个背景下,侧边导航栏要解决的不是"好看",而是"让用户在正确的信息层级里流畅地找到功能"。
1.2 侧边导航和顶部导航,我为什么选侧边
顶部导航不是不能用,但在这个项目里它已经走到极限:菜单项超出屏幕宽度、子菜单下拉层级混乱,移动端更是直接摊成一大坨。侧边导航栏的优势在于纵向空间天然够用,可以容纳更深的菜单层级,而且左侧固定、右侧内容区滚动,是非常成熟的二维导航模式。
用表格快速对比一下:
| 维度 | 顶部导航 | 侧边导航栏 |
|---|---|---|
| 容纳菜单数量 | 受屏幕宽度限制,一般 5-8 个 | 受高度限制,几十个都没问题 |
| 子菜单展示 | 下拉,层级难以直观体现 | 缩进 + 展开收起,层级清晰 |
| 操作路径长度 | 鼠标移动距离中 | 鼠标纵向移动,距离短 |
| 小屏适配 | 折叠成汉堡,实现简单 | 需要抽屉化处理,复杂度高 |
| 内容区宽度 | 完整内容宽度 | 内容区变窄,需要重新平衡 |
后台管理、文档站点、SaaS 控制台这类场景,侧边导航栏几乎是标配。如果你手头是偏展示型的官网,顶部导航或页脚导航可能更合适。这个选择一定要在开工前想清楚,因为改起来成本不低。
2. 真正动手前,先把三件事定下来
2.1 把菜单层级梳理成一份可落地的结构
别急着写代码,第一件事是拉上需求方把所有页面过一遍,整理出菜单的树形结构。这个结构决定后续页面上每个功能入口怎么分组、怎么排序、哪些菜单需要二级折叠、哪些直接展示。我习惯做成一份 Markdown 表格,字段包括:菜单名称、父级菜单、目标路由、显示顺序、是否默认展开。
实际梳理出来的结果是 7 个一级菜单,其中 3 个带有子菜单,总页面数量约 40 个。这份清单不仅是开发依据,也是后续验收的标准。没有这一步,开发中途必然出现"这个功能放哪个菜单下"的无休止争论。
2.2 页面骨架怎么切:栅格比例和内容区重建
Bootstrap 3 的栅格系统默认 12 列,侧边导航我选了col-sm-3,内容区用col-sm-9,比例大概 1:3。这个比例在 14 到 15 英寸笔记本上,侧边栏宽度约 240-270px,对菜单文字来说比较舒适,内容区也不会太挤。如果你菜单文案太长,可以考虑col-sm-3加col-sm-8,留一列做呼吸空间。
我采用的页面骨架大致是:
<body> <header class="navbar navbar-inverse navbar-fixed-top"> <!-- 顶部内容,保持原来的系统入口 --> </header> <div class="container-fluid" style="margin-top: 70px;"> <div class="row"> <div class="col-sm-3"> <aside class="sidebar-menu"> <!-- 侧边导航主体 --> </aside> </div> <div class="col-sm-9"> <main class="main-content"> <!-- 各业务页面内容 --> </main> </div> </div> </div> </body>这里的container-fluid是为了让内容铺满相对宽度,后台系统很少用固定宽度容器。顶部固定导航栏的高度要单独预留,否则侧边栏会被遮住。我用的是margin-top: 70px,这个值要根据你自己导航栏的实际高度调整,不能抄别人的。
2.3 交互状态确认:展开、高亮、滚动跟随
交互状态在写代码前一定跟需求方对齐,否则返工率极高。侧边导航栏最常见的状态有三种:当前菜单高亮、子菜单展开收起、滚动时导航栏固定和内容位置高亮。我的处理方案是:
- 当前高亮:默认匹配浏览器地址栏路径,页面加载后自动定位到对应菜单项并加 active 样式。
- 子菜单收起:默认只展开当前路径所在的父级菜单,其余全部收起,减少信息噪音。
- 滚动固定:内容页较长时,侧边栏保持在视口内不滚走,用 Affix 实现。
- 滚动高亮:仅单页长文档场景使用 Scrollspy,多页面系统不做,加了反而让用户困惑。
这些状态后续在所有公共页面模板里统一套用,所以提前确认清楚非常关键。
3. 侧边导航栏主体实现:从静态列表到可收展菜单
3.1 用 Bootstrap 3 自带组件搭起静态骨架
Bootstrap 3 的nav组件配合nav-stacked类,可以快速做出竖向菜单的基本样式。我自己会以nav-pills为基础,这样结合nav-stacked后,菜单项默认就有圆角背景高亮效果,视觉上更像一个标准左侧导航。
基础结构这样写:
<aside class="sidebar-menu"> <ul class="nav nav-pills nav-stacked sidebar-nav"> <li class="active"><a href="/dashboard"><i class="glyphicon glyphicon-home"></i> 工作台</a></li> <li> <a href="#orderMenu">$(document).ready(function () { // 点击父菜单时切换箭头方向 $('.sidebar-nav [data-toggle="collapse"]').on('click', function () { $(this).find('.glyphicon-chevron-down') .toggleClass('glyphicon-chevron-up'); }); // 页面加载后根据 URL 高亮当前菜单 var currentPath = window.location.pathname; $('.sidebar-nav a[href]').each(function () { var href = $(this).attr('href'); if (href && currentPath.indexOf(href) !== -1) { $(this).parent().addClass('active'); // 如果有父级菜单,把父级展开 $(this).parents('.collapse').addClass('in'); } }); });addClass('active')放在li上,这是 Bootstrap 3 高亮规则的核心。如果当前路径既是子页面又是父级菜单入口,这段代码会同时高亮父级和子级,实际使用时可以根据需求加not()过滤。总之,用事件委托比在每个菜单上单独绑事件要省事得多,菜单如果是后端动态渲染的,这段逻辑同样适用。
3.3 当前项高亮的两种常见策略
高亮策略我见过程序员朋友用过两种:后端渲染法和前端 URL 匹配法。如果你是服务端模板渲染,比如 JSP、Freemarker、PHP 模板,最佳方案是在后端输出菜单时直接根据当前路由生成 active 类名,不依赖任何 JavaScript。这种方案最稳,刷新页面、浏览历史返回时都不会闪。
如果项目是前后端分离或者静态页,就采用我上面那套前端 URL 匹配。注意要把indexOf换成更严格的匹配逻辑,避免出现/orders/和/orders/export互相误匹配的情况:
function isMenuActive(menuHref, currentPath) { if (menuHref === '/') { return currentPath === '/'; } return currentPath.indexOf(menuHref) === 0 && (currentPath.length === menuHref.length || currentPath.charAt(menuHref.length) === '/'); }这样能规避大部分匹配错误。但真实项目里还会遇到带查询参数、带 hash 的 URL,要根据实际路由形态微调。没有匹配规则能做到万能,关键是让开发者在每页都能明确知道"当前在哪"。
4. 让侧边栏"粘"在视口里,并让阅读位置实时高亮
4.1 Affix 让导航栏固定在视口内,但小心宽度塌陷
内容页一旦很长,用户向下滚动后侧边导航就看不到了,这个体验很糟。Bootstrap 3 提供了 Affix 插件来把元素固定在视口内,使用很简单,加两个 data 属性:
<aside class="sidebar-menu">.sidebar-affix-wrapper { position: relative; } .sidebar-affix-wrapper .affix { top: 70px; /* 顶部导航高度 */ width: inherit; }把 Affix 放到一个带position: relative的父容器里,width: inherit会让固定后的侧边栏保持原来col-sm-3的宽度。这个方案兼容性很好,不需要担心响应式断点变化时写死像素失效。
4.2 Scrollspy 只适合单页长文档,别在多页面里硬套
Scrollspy 是 Bootstrap 3 里跟 Affix 常配合的另一个插件:页面滚动时,根据内容当前位置自动高亮对应导航项。它的使用条件很关键——只适合单页内锚点跳转,也就是href="#section1"这种场景。我第一版想把它用在整个后台系统里,结果发现每点一个菜单就跳转到新 URL,Scrollspy 根本感知不到,完全失灵。
如果确实需要在普通页面用,必须给 body 加上><body><button type="button" class="btn btn-default visible-xs sidebar-toggle"> <span class="glyphicon glyphicon-menu-hamburger"></span> 菜单 </button> <div class="sidebar-overlay"></div> <aside class="sidebar-menu"> <!-- 原菜单 --> </aside>
对应 CSS:
@media (max-width: 767px) { .sidebar-menu { position: fixed; left: -280px; top: 0; bottom: 0; width: 280px; background: #fff; z-index: 1050; transition: left 0.25s ease; overflow-y: auto; } .sidebar-menu.open { left: 0; } .sidebar-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.4); z-index: 1040; } .sidebar-overlay.show { display: block; } }按钮点击事件就两个:addClass('open')显示抽屉,点遮罩或点击菜单项后移除open和show。注意抽屉的z-index必须大于遮罩,遮罩又要盖过页面其他内容,基本是1040/1050这样的层级搭配。
5.2 遮罩和滚动穿透,这两个细节别偷懒
加遮罩是为了让用户点击抽屉外区域直接关闭,这是移动端最符合直觉的交互方式。遮罩还有一个作用:视觉上把菜单和内容区隔离,避免误操作。
比遮罩更隐蔽的坑是滚动穿透。抽屉打开后,如果用户手指在遮罩或菜单上滑动,页面底层的 body 也在跟着滚动,体验很糟糕。我的修复方式是在抽屉打开时给 body 加overflow: hidden,关闭后移除:
$('#sidebar').on('show', function () { $('body').css('overflow', 'hidden'); }); $('#sidebar').on('hide', function () { $('body').css('overflow', ''); });这里要注意,如果项目里已有别的弹窗组件也在改 body 的 overflow,会引起状态互相覆盖。稳妥的办法是用一个计数器管理开关状态,只有全部关闭后才恢复 body 滚动。
6. 实测中踩过的坑和一套通用排查思路
6.1 点击菜单后页面刷新,高亮却丢了
最常见的现象是:用户进入/orders/pending页面,菜单里的"全部订单"还亮着,或者整片菜单没有一个高亮项。原因通常是 URL 匹配逻辑没考虑带根路径或带 query 的地址。我之前用indexOf(href)匹配/orders/pending时,/orders和/orders/pending会同时命中,导致两个菜单都被点亮。后来改成上面那版严格匹配函数,问题才彻底解决。
排查思路是:在浏览器控制台输出当前location.pathname和所有菜单项的 href,一点点对比匹配过程,比盲改代码高效得多。
6.2 子菜单默认展开状态不对,箭头方向也怪
Bootstrap 3 的collapse插件判断初始状态靠的是有没有in类。如果某个父级菜单需要默认展开,直接在对应子菜单 ul 上加上in,否则用 JS 根据当前路径动态添加。箭头方向问题,我见过很多人在 CSS 里写transform: rotate,但更省事的方案是像前面那样在 HTML 里就放一个跟业务关联的旋转图标类,脚本里去切换。
排查这个小问题时要确认页面上是否只加载了一个 Bootstrap JS 文件。老系统经常在全局模板里引入一次,业务页面又引入一次,插件事件会触发两遍,表现为代码明明写了,但行为时好时坏。
6.3 侧边栏和现有 tab 插件互相打架
旧系统里一般会有自己封装的 tab 切换、弹窗、tooltip 逻辑,它们常常也在操作 body class 或全局事件。我遇到过一次:侧边栏的抽屉遮罩把另一个 Bootstrap Modal 的遮罩盖住了,导致弹窗打开后无法点击,看起来像卡死。
排查方法是优先确认 z-index 层级关系,其次看两个组件是否用了同名 class。我的建议是给侧边栏的 DOM 元素都加上sidebar-前缀,避免跟业务系统的命名冲突。虽然丑了点,但大巴车系统的稳定性比命名美感重要得多。
这些坑说到底是渐进增强和全局污染的问题。在一个使用多年的 Bootstrap 3 系统里加点新功能,最大的敌人不是语法,而是历史包袱。每覆盖掉一个全局样式,都要警惕它是不是另一个模块正在依赖的东西。
最后分享一个我在这个项目里落地的实用技巧:把侧边导航栏拆成一个公共模板片段,菜单结构用一个 JSON 对象维护,前端循环渲染。以后新增页面只需要改一份数据源,不需要再复制粘贴整个导航代码。老项目里的迭代,最怕的就是同样的逻辑散落十几处。一个能长期维护的侧边导航栏,比一个技术上漂亮的导航栏更重要。
本文还有配套的精品资源,点击获取