如何实现滚动时自动隐藏/显示头部横幅的纯 JS/CSS 解决方案

3次阅读

如何实现滚动时自动隐藏/显示头部横幅的纯 JS/CSS 解决方案

本文介绍一种无需 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 实现更精细的视口控制。

text=ZqhQzanResources