使用纯 JavaScript (最常用)
这是最核心、最直接的实现方式,理解了它,你就掌握了这个效果的精髓。

(图片来源网络,侵删)
实现原理
- 监听滚动事件:使用
window.addEventListener('scroll', ...)来监听用户滚动页面的行为。 - 获取滚动位置:在滚动事件触发时,通过
window.scrollY或window.pageYOffset获取当前页面垂直滚动的距离。 - 判断滚动方向:通过比较当前滚动位置和上一次的滚动位置,来判断用户是向上还是向下滚动。
- 添加/移除类:根据滚动方向和预设的阈值(比如滚动超过50px才触发),给导航栏元素添加或移除一个控制显示/隐藏的CSS类(
.hide)。 - 优化性能:滚动事件会非常频繁地触发,所以需要使用 防抖 或 节流 来优化性能,避免浏览器卡顿。
完整代码示例
HTML 结构
创建一个简单的导航栏和一些占位内容,以便可以滚动。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">滚动导航消失效果</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav id="navbar">
<div class="logo">我的Logo</div>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">lt;/a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系</a></li>
</ul>
</nav>
<main>
<h1>向下滚动,导航栏会消失</h1>
<p>向上滚动,导航栏会重新出现。</p>
<!-- 为了演示,添加很多占位内容 -->
<div style="height: 2000px; background: linear-gradient(to bottom, #f0f0f0, #e0e0e0);">
<p style="text-align: center; margin-top: 1000px;">滚动到这里试试看</p>
</div>
</main>
<script src="script.js"></script>
</body>
</html>
CSS 样式
这里我们定义导航栏的默认样式和隐藏时的样式。

(图片来源网络,侵删)
/* style.css */
body {
margin: 0;
font-family: sans-serif;
}
#navbar {
position: fixed; /* 关键:固定定位 */
top: 0;
left: 0;
width: 100%;
background-color: #333;
color: white;
padding: 15px 0;
text-align: center;
z-index: 1000; /* 确保导航栏在最上层 */
transition: top 0.3s ease-in-out; /* 关键:添加平滑过渡效果 */
}
#navbar .logo {
float: left;
padding: 0 20px;
font-weight: bold;
}
#navbar ul {
list-style-type: none;
margin: 0;
padding: 0;
float: right;
}
#navbar ul li {
display: inline;
}
#navbar ul li a {
color: white;
text-decoration: none;
padding: 0 20px;
}
/* 定义隐藏状态的类 */
#navbar.hide {
top: -60px; /* 将导航栏向上移动,完全移出视口 */
}
main {
padding-top: 60px; /* 为内容添加内边距,避免被固定的导航栏遮挡 */
}
JavaScript 逻辑
这是实现效果的核心代码,包含了滚动方向判断和节流优化。
// script.js
document.addEventListener('DOMContentLoaded', () => {
const navbar = document.getElementById('navbar');
let lastScrollTop = 0; // 记录上一次的滚动位置
// 使用节流函数来优化性能
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
window.addEventListener('scroll', throttle(() => {
// 获取当前滚动位置
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// 判断滚动方向
if (scrollTop > lastScrollTop && scrollTop > 100) {
// 向下滚动,并且滚动超过100px
navbar.classList.add('hide');
} else {
// 向上滚动
navbar.classList.remove('hide');
}
// 更新上一次的滚动位置
lastScrollTop = scrollTop;
}, 150)); // 150ms的节流时间
});
使用 CSS (更简单,但有局限性)
如果不需要考虑滚动方向,只要滚动就隐藏,这个方法最简单。
实现原理
利用 target 伪类,我们创建一个隐藏的锚点,当页面滚动到这个锚点时,target 生效,改变导航栏的样式。

(图片来源网络,侵删)
完整代码示例
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">CSS滚动隐藏</title>
<link rel="stylesheet" href="css-only-style.css">
</head>
<body>
<!-- 隐藏的锚点,当页面滚动到这里时触发效果 -->
<a id="hide-nav"></a>
<nav id="navbar">
<div class="logo">我的Logo</div>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#hide-nav">隐藏我</a></li> <!-- 点击此链接会触发效果 -->
<li><a href="#">lt;/a></li>
<li><a href="#">服务</a></li>
</ul>
</nav>
<main>
<h1>点击导航栏中的“隐藏我”链接</h1>
<p>导航栏会隐藏,点击浏览器的前进/后退按钮可以恢复。</p>
<div style="height: 2000px; background: #f5f5f5;"></div>
</main>
</body>
</html>
CSS
/* css-only-style.css */
body {
margin: 0;
font-family: sans-serif;
}
#navbar {
position: fixed;
top: 0;
width: 100%;
background-color: #333;
color: white;
padding: 15px 0;
text-align: center;
transition: top 0.3s ease-in-out;
}
#navbar .logo {
float: left;
padding: 0 20px;
font-weight: bold;
}
#navbar ul {
list-style-type: none;
margin: 0;
padding: 0;
float: right;
}
#navbar ul li {
display: inline;
}
#navbar ul li a {
color: white;
text-decoration: none;
padding: 0 20px;
}
/* 核心:当页面URL的target是#hide-nav时,隐藏导航栏 */
body:target #navbar {
top: -60px;
}
main {
padding-top: 60px;
}
局限性:
- 不智能:它只响应URL的
target变化,而不是真实的滚动行为。 - 交互差:用户必须点击特定链接才能触发,不符合“自然滚动”的直觉。
- 恢复困难:通常需要用户点击浏览器的前进/后退按钮才能恢复导航栏。
使用 JavaScript 库 (如 Headroom.js)
对于追求专业效果和健壮性的项目,使用现成的库是最好的选择。
实现原理
Headroom.js 是一个专门为此效果设计的轻量级库,它封装了所有的逻辑,包括滚动方向判断、防抖、元素状态管理等,并提供了一些高级选项,如 pin(固定在顶部)和 offset(偏移量)。
完整代码示例
安装 Headroom.js 可以通过 npm 或直接使用 CDN。
HTML HTML 结构和方案一基本一样。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">Headroom.js 滚动隐藏</title>
<link rel="stylesheet" href="headroom-style.css">
<!-- 引入 Headroom.js -->
<script src="https://cdn.jsdelivr.net/npm/headroom.js@0.12.0/dist/headroom.min.js"></script>
</head>
<body>
<nav id="navbar">
<div class="logo">Headroom.js Logo</div>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">lt;/a></li>
<li><a href="#">服务</a></li>
<li><a href="#">联系</a></li>
</ul>
</nav>
<main>
<h1>使用 Headroom.js 实现的专业滚动效果</h1>
<p>这个库处理了所有复杂的边缘情况,效果非常流畅。</p>
<div style="height: 2000px; background: linear-gradient(to bottom, #4facfe, #00f2fe);">
<p style="text-align: center; margin-top: 1000px; color: white;">滚动到这里试试看</p>
</div>
</main>
<script src="headroom-script.js"></script>
</body>
</html>
CSS
CSS 也和方案一类似,但 Headroom.js 会动态添加 headroom, pinned, unpinned 等类。
/* headroom-style.css */
body {
margin: 0;
font-family: sans-serif;
}
#navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: #333;
color: white;
padding: 15px 0;
text-align: center;
z-index: 1000;
/* Headroom.js 会添加 transition 类 */
transition: transform 0.3s ease-in-out;
}
/* Headroom.js 添加的类 */
#navbar.headroom {
transition: transform 0.3s ease-in-out;
}
#navbar.headroom--pinned {
/* 固定在顶部时的样式 */
transform: translateY(0);
}
#navbar.headroom--unpinned {
/* 从顶部消失时的样式 */
transform: translateY(-100%);
}
#navbar .logo {
float: left;
padding: 0 20px;
font-weight: bold;
}
#navbar ul {
list-style-type: none;
margin: 0;
padding: 0;
float: right;
}
#navbar ul li {
display: inline;
}
#navbar ul li a {
color: white;
text-decoration: none;
padding: 0 20px;
}
main {
padding-top: 60px;
}
JavaScript 使用 Headroom.js 只需几行代码。
// headroom-script.js
document.addEventListener('DOMContentLoaded', () => {
const navbar = document.querySelector("#navbar");
// 初始化 Headroom
const headroom = new Headroom(navbar, {
// 可选配置
tolerance: 5, // 滚动多少距离才触发
offset: 80, // 滚动多少距离才隐藏
// 还可以配置 'pin'、'unpin' 等事件的回调函数
});
// 启动
headroom.init();
});
总结与对比
| 特性 | 方案一 (原生 JS) | 方案二 (纯 CSS) | 方案三 (Headroom.js) |
|---|---|---|---|
| 实现复杂度 | 中等 | 非常低 | 非常低 |
| 灵活性 | 极高,可完全自定义 | 极低,功能受限 | 高,有丰富配置选项 |
| 性能 | 良好(需手动优化) | 极佳 | 极佳(库已优化) |
| 用户体验 | 好,符合直觉 | 差,交互不自然 | 极佳,效果专业流畅 |
| 适用场景 | 大多数自定义项目 | 简单、静态页面,或特殊需求 | 专业项目,追求最佳效果和健壮性 |
推荐选择:
- 学习或快速实现:选择 方案一,它能帮你深刻理解原理。
- 简单静态页面:如果只是做一个简单的展示页,方案二 可以快速搞定。
- 商业项目或追求完美:强烈推荐 方案三,
Headroom.js是业界的标准解决方案,稳定可靠。
