You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据滚动位置逐像素控制导航栏显隐实现跟手滚动动画

逐像素跟手的滚动导航栏实现方案

常见跳变方案的问题

目前网上大部分导航栏滚动隐藏的实现,都是通过判断滚动方向后直接切换固定CSS样式实现,代码如下:

var lastScrollTop; // 存储上一次滚动位置
navbar = document.getElementById('navbar'); // 获取导航栏元素

window.addEventListener('scroll',function(){
  var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  if(scrollTop > lastScrollTop){ // 向下滚动时直接隐藏
    navbar.style.top='-80px';
  }
  else{ // 向上滚动时直接显示
    navbar.style.top='0';
  }
  lastScrollTop = scrollTop;
});

配套的基础样式:

body{
  margin:0;
  padding:0;
}
.container{
  background:url('https://images.unsplash.com/photo-1497250681960-ef046c08a56e') no-repeat center center;
  height:170vh;
}
#navbar{
  position:fixed;
  top:0;
  left:0;
  width:100%;
  background:blue;
  border-radius:0 0 30px 30px;
  color:white;
  text-align:center;
  height:80px;
  transition: 0.5s;
}

footer{
  text-align:center;
  position:relative;
  bottom:0;
  left:0;
}

基础HTML结构:

<div class="container">
  <navbar id="navbar">
    <h1>NAVBAR<h1>
  </navbar>
</div>
<footer>
  <h3>End of the Page</h3>
</footer>

这类方案的问题很明显:导航栏的显示/隐藏是跳变的,即使加了CSS过渡,也无法做到和用户滚动操作完全同步的跟手效果。

跟手效果实现逻辑

要实现滚动1像素导航栏同步移动1像素的效果,核心是放弃方向判断后的固定样式切换,把滚动差值直接映射为导航栏的偏移量,遵循以下规则:

  • 导航栏高度固定为80px,初始状态完全可见,偏移量为0
  • 每次滚动时计算本次滚动的距离差值:向下滚动差值为正,向上滚动差值为负
  • 导航栏偏移量和滚动差值反向计算:向下滚多少像素,导航栏就向上偏移多少像素(隐藏对应距离);向上滚多少像素,导航栏就向下偏移多少像素(显示对应距离)
  • 偏移量始终限制在[-80px, 0]区间内:最小偏移-80px(完全隐藏),最大偏移0(完全显示),不会出现超出范围的异常位置

最终实现代码

优化后的JS逻辑

这里用transform: translateY实现偏移,比修改top性能更好,不会触发页面重排;滚动事件加passive标记提升滚动响应速度:

const navbar = document.getElementById('navbar');
const NAV_BAR_HEIGHT = 80; // 和CSS中导航栏高度保持一致
let lastScrollY = window.scrollY;
let currentNavOffset = 0; // 记录导航栏当前偏移量,初始为0完全可见

window.addEventListener('scroll', () => {
  const currentScrollY = window.scrollY;
  const scrollDelta = currentScrollY - lastScrollY; // 计算本次滚动的距离差

  // 更新导航栏偏移量
  currentNavOffset -= scrollDelta;
  // 钳制偏移量在合法区间
  currentNavOffset = Math.max(-NAV_BAR_HEIGHT, Math.min(0, currentNavOffset));

  // 应用偏移,不需要加CSS过渡,实时跟手
  navbar.style.transform = `translateY(${currentNavOffset}px)`;

  lastScrollY = currentScrollY;
}, { passive: true });

调整后的CSS

移除原方案中导航栏的transition属性(加过渡会导致跟手延迟),增加性能优化配置:

body{
  margin:0;
  padding:0;
}
.container{
  background:url('https://images.unsplash.com/photo-1497250681960-ef046c08a56e') no-repeat center center;
  height:170vh;
}
#navbar{
  position:fixed;
  top:0;
  left:0;
  width:100%;
  background:blue;
  border-radius:0 0 30px 30px;
  color:white;
  text-align:center;
  height:80px;
  will-change: transform; /* 提示浏览器提前做GPU渲染优化 */
}

footer{
  text-align:center;
  position:relative;
  bottom:0;
  left:0;
}

HTML结构不需要改动,和之前保持一致即可。

效果参考

Medium移动端底部浮层跟手滚动演示

如果需要进一步优化性能,可以把滚动事件里的DOM更新逻辑放到requestAnimationFrame中执行,避免短时间内多次触发重绘。

内容的提问来源于stack exchange,提问作者Niklas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:09:23