一段可直接落地的导航栏
导航栏是几乎所有网站的标配,也是响应式改造里最容易返工的部分:桌面端好好的菜单,到手机上要么挤成一团,要么只能靠浏览器自带的"放大"勉强操作。下面这个组件把常见需求一次打包——粘性置顶、移动端汉堡菜单、下拉子菜单、当前页面高亮,外加 CTA 按钮和无障碍标签,复制即可用。
组件不含任何框架依赖,纯 HTML/CSS/JavaScript 实现,方便接入任意项目。它适合三类典型站点:内容型博客(菜单简单、突出阅读)、企业展示站(用"服务"下拉做分类)、带转化的营销页(用 CTA 按钮引导咨询)。不同站点只需调整菜单结构与高亮逻辑,布局骨架可以复用。整体验收时,可以对照 响应式布局验收清单 逐项检查。
HTML
<nav class="navbar">
<div class="nav-container">
<a href="/" class="nav-logo">
<img src="logo.svg" alt="Logo" height="32">
</a>
<button class="nav-toggle" aria-label="切换菜单">
<span></span>
<span></span>
<span></span>
</button>
<ul class="nav-menu">
<li><a href="/" class="active">首页</a></li>
<li class="dropdown">
<a href="/services">服务 ▾</a>
<ul class="dropdown-menu">
<li><a href="/web-design">网页设计</a></li>
<li><a href="/hosting">主机托管</a></li>
<li><a href="/seo">SEO 优化</a></li>
</ul>
</li>
<li><a href="/about">关于</a></li>
<li><a href="/blog">博客</a></li>
<li><a href="/contact" class="nav-cta">联系我们</a></li>
</ul>
</div>
</nav>
CSS
/* 基础样式 */
.navbar {
background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,.1);
position: sticky;
top: 0;
z-index: 1000;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
height: 64px;
}
.nav-menu {
display: flex;
list-style: none;
gap: 8px;
margin: 0;
padding: 0;
}
.nav-menu a {
text-decoration: none;
color: #333;
padding: 8px 16px;
border-radius: 6px;
transition: background .2s;
}
.nav-menu a:hover,
.nav-menu a.active {
background: #f0f0f0;
color: #4F46E5;
}
.nav-cta {
background: #4F46E5;
color: #fff !important;
}
.nav-cta:hover {
background: #4338CA !important;
}
/* 下拉菜单 */
.dropdown { position: relative; }
.dropdown-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
box-shadow: 0 4px 12px rgba(0,0,0,.1);
border-radius: 8px;
min-width: 180px;
list-style: none;
padding: 8px;
}
.dropdown:hover .dropdown-menu {
display: block;
}
/* 汉堡按钮 */
.nav-toggle {
display: none;
flex-direction: column;
gap: 5px;
background: none;
border: none;
cursor: pointer;
padding: 4px;
}
.nav-toggle span {
display: block;
width: 24px;
height: 2px;
background: #333;
transition: transform .3s;
}
/* 移动端 */
@media (max-width: 768px) {
.nav-toggle { display: flex; }
.nav-menu {
display: none;
position: absolute;
top: 64px;
left: 0;
right: 0;
background: #fff;
flex-direction: column;
padding: 16px;
box-shadow: 0 4px 12px rgba(0,0,0,.1);
}
.nav-menu.active { display: flex; }
.dropdown-menu {
position: static;
box-shadow: none;
padding-left: 16px;
}
}
JavaScript
document.addEventListener('DOMContentLoaded', () => {
const toggle = document.querySelector('.nav-toggle');
const menu = document.querySelector('.nav-menu');
toggle.addEventListener('click', () => {
menu.classList.toggle('active');
toggle.setAttribute('aria-expanded',
toggle.getAttribute('aria-expanded') === 'false' ? 'true' : 'false'
);
});
// 点击菜单外关闭
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar')) {
menu.classList.remove('active');
}
});
});
功能特性
- ✅ 粘性导航(Sticky Header)
- ✅ 移动端汉堡菜单
- ✅ 下拉菜单(子导航)
- ✅ 当前页面高亮(.active)
- ✅ 点击外部关闭菜单
- ✅ ARIA 无障碍标签
- ✅ CTA 按钮样式
接入要点
拿到模板后接入时注意三个细节。第一,logo 路径与菜单链接要替换成你的真实地址;第二,把 .active 类加到当前页面对应的菜单项上,高亮由纯 CSS 完成,不需要额外 JS;第三,如果项目已经在用 Bootstrap、Tailwind 之类的框架,可以只保留交互逻辑,把样式换成框架类名。
如果菜单需要服务端渲染,比如配合 Next.js 或 Vue 3,建议直接把当前路由渲染成 .active,避免刷新后高亮丢失。
扩展与定制
基础的骨架有了,剩下按站点需要做三件常见的扩展:
多级下拉。 服务分类超过一层时,在 .dropdown-menu 里再加一组 <ul> 并让二级菜单横向浮出。注意移动端断点内要把多级下拉也改回纵向堆叠,否则触屏上很难操作。
搜索框。 把搜索表单放进 .nav-container,在移动端默认隐藏,点击搜索图标再展开。搜索框宽度用 min(320px, 100%) 保证小屏不溢出。
暗色模式。 用 CSS 变量接管背景和文字颜色,例如:
.navbar { background: var(--nav-bg, #fff); }
@media (prefers-color-scheme: dark) {
:root { --nav-bg: #1f2937; --nav-text: #f9fafb; }
}
滚动反馈。 向下滚动时让导航收起、向上滚动时重新露出,既能提升阅读空间,也能避免 position: sticky 在长页面占位。这类交互要配合 requestAnimationFrame 做节流,避免频繁读写布局。
字体、间距、图标这类视觉细节,可以交给设计规范统一处理,参考 设计系统组件 和 现代 CSS 布局。
无障碍细节
aria-expanded会随菜单开关同步更新,读屏软件能感知菜单状态;- 汉堡按钮的
aria-label="切换菜单"明确了按钮用途; - 下拉目前依赖 hover,建议补充
:focus-within,让键盘用户也能展开子菜单:
.dropdown:focus-within .dropdown-menu { display: block; }
- 移动端菜单打开后,可以把焦点移到第一个菜单项,避免键盘用户"迷失"在页面里。完整的无障碍规范可参考 网站无障碍指南。
性能与兼容提示
- 全站菜单建议在关键页面内联首屏 CSS,避免导航在样式加载前闪动(FOUC);
- 图标用内联 SVG 或 iconfont,比一张整图少一次请求;
- 菜单项不超过 8 个时,可以不引入 JS 框架,原生代码已足够;
- 老版本浏览器(如 IE)需要
@supports或降级样式兜底,目前主流浏览器均已支持 flex。
常见问题
为什么用 position: sticky 而不是 fixed? 导航在页面顶部时两者表现一致,但 sticky 会保留自身占位、不脱离文档流;当导航不是页面第一个元素时,fixed 会把内容顶到导航下方造成遮挡,sticky 不会有这个问题。
下拉菜单在触屏上点不开? 默认实现依赖 hover,触屏的第一次点击会先触发 hover 而不是跳转。建议在移动端断点内把下拉改成点击切换,或直接展示静态子菜单。
一级菜单项多了怎么办? 超过 6-7 项时横向空间吃紧。常见做法是把次要入口收进"更多"下拉,或用图标加文字的组合压缩宽度。
页面还有别的吸顶元素(如公告栏)怎么办? 给 .navbar 设置 top: 40px(公告栏高度)即可让导航吸附在公告栏下方;多个吸顶元素并存时,按层级用 z-index 排序即可。
点击汉堡按钮后菜单没有展开? 多半是 JS 没加载成功,或 .nav-toggle 与 .nav-menu 的类名被框架覆盖。先打开控制台确认没有报错,再检查 menu.classList.toggle('active') 对应的选择器是否与实际 DOM 一致。
参考:MDN
<nav>元素 — https://developer.mozilla.org/docs/Web/HTML/Element/nav ;WAI-ARIA Menu Pattern — https://www.w3.org/WAI/ARIA/apg/patterns/menu/