
本文介绍一种无需 jQuery 的轻量级方案:通过 vanilla JavaScript 监听滚动方向 + CSS position: sticky 分层控制,实现「向下滚动隐藏顶部横幅、向上滚动恢复显示」,同时确保主导航栏始终吸附顶部。
本文介绍一种无需 jquery 的轻量级方案:通过 vanilla javascript 监听滚动方向 + css `position: sticky` 分层控制,实现「向下滚动隐藏顶部横幅、向上滚动恢复显示」,同时确保主导航栏始终吸附顶部。
在现代网页中,智能头部(Smart Header)已成为提升用户体验的重要交互模式——它能减少视觉干扰、释放内容空间,又能在用户回溯意图明确时快速回归导航入口。本教程将基于纯 CSS 与原生 JavaScript,构建一个双层头部结构:上层为可折叠的「精简横幅(skinny banner)」,下层为主导航栏(main-nav)。关键要求是:
- ✅ 向下滚动时,横幅平滑隐藏;
- ✅ 向上滚动时,横幅平滑浮现;
- ✅ 主导航栏始终保持 sticky 状态,且在横幅隐藏后直接贴顶(无空白间隙);
- ❌ 不依赖 jQuery 或第三方库。
核心思路:分离粘性行为,用 JS 控制显隐
CSS 的 position: sticky 本身不具备“滚动方向感知”能力,因此需结合 JavaScript 判断滚动趋势。但注意:不要给整个 .header-container 设置 sticky —— 这会导致横幅与导航被绑定为同一粘性单元,无法独立控制显隐。正确做法是:
- ✨ 仅对 .main-nav 应用 position: sticky; top: 0;,使其成为真正“永远钉在顶部”的容器;
- ✨ 将 .skinny-banner 设为普通文档流元素(或相对定位),通过 JS 动态切换其 transform: translateY() 或 opacity/height,配合 CSS transition 实现流畅动画。
完整实现代码
✅ HTML 结构(语义清晰,层级合理)
<div class="header-container"> <div class="skinny-banner">Skinny banner that should hide when scrolling down and appear when scrolling up</div> <div class="main-nav">Should always be visible and should pin to top when skinny banner is hidden</div> </div> <div class="dummy-content"></div>
✅ CSS 样式(重点:sticky 作用于 main-nav,横幅保留过渡)
body {
margin: 0;
}
.skinny-banner {
background-color: #2e7d32; /* 更规范的绿色 */
height: 40px;
color: white;
text-align: center;
line-height: 40px;
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.25s ease;
will-change: transform, opacity;
}
/* 向上滚动时显示,向下滚动时隐藏 */
.skinny-banner.hidden {
transform: translateY(-100%);
opacity: 0;
}
.main-nav {
min-height: 112px;
background-color: #000;
color: white;
text-align: center;
line-height: 112px;
position: sticky;
top: 0;
z-index: 100; /* 确保覆盖滚动内容 */
}
.dummy-content {
background-color: #fff9c4;
height: 2000px; /* 增加高度便于测试滚动 */
padding: 2rem;
}✅ Vanilla JavaScript(轻量、防抖、方向判断)
let lastScrollTop = 0;
const banner = document.querySelector('.skinny-banner');
const headerContainer = document.querySelector('.header-container');
// 使用 passive: true 提升滚动性能
window.addEventListener('scroll', () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop > lastScrollTop && scrollTop > 60) {
// 向下滚动且超过初始阈值(避免首页微动误触发)
banner.classList.add('hidden');
} else if (scrollTop < lastScrollTop) {
// 向上滚动 → 显示横幅
banner.classList.remove('hidden');
}
lastScrollTop = scrollTop <= 0 ? 0 : scrollTop; // 防止负值
}, { passive: true });
// 可选:页面加载时初始化状态(如从锚点跳转后重置)
window.addEventListener('load', () => {
banner.classList.remove('hidden');
});⚠️ 关键注意事项
- z-index 必须设置:.main-nav 的 z-index 需高于后续内容,否则滚动时可能被遮挡;
- will-change 提升性能:对 transform 和 opacity 添加 will-change,触发 GPU 加速;
- 滚动阈值(60px)建议保留:防止用户轻微滚动(如触摸屏惯性滑动)导致横幅频繁闪现;
- 避免 display: none:它会破坏文档流并中断 CSS 过渡,务必使用 transform + opacity 组合控制;
- 移动端兼容性:position: sticky 在 iOS Safari 15.4+ 和 Android Chrome 56+ 中已全面支持,旧版可添加渐进增强降级逻辑。
✅ 总结
该方案以“分治思想”解耦粘性与显隐逻辑:CSS 负责声明式布局约束(sticky on .main-nav),JavaScript 专注行为感知(滚动方向判定),两者协同达成丝滑体验。代码体积小、可维护性强,且完全符合现代 Web 性能最佳实践。你可根据项目需求进一步扩展,例如添加滚动节流、支持自定义触发距离、或集成 Intersection Observer 实现更精细的视口控制。










