应使用transform: translateY()配合滚动方向判断,而非top:因top触发重排卡顿,transform走合成层更顺;需节流150ms、设5px阈值防抖,监听wheel事件统一用deltaY,并兼顾touch和软键盘场景。

直接用 transform: translateY() 配合 JS 滚动方向判断,比只靠 top 切换更稳、更顺。单纯监听 scroll 事件 + 差值判断方向,在 macOS 触控板或鼠标滚轮抖动时极易误判,导致导航栏反复闪动。
为什么 scroll + deltaY 容易闪动
滚动惯性、触摸板加速、滚轮采样噪声会让 window.scrollY 的单次差值在 ±1px 间跳变,尤其在慢速滚动时。仅靠 currentScrollY - lastScrollY > 0 判定“向下”,等于把毛刺当信号。
- 改用「滚动停止后更新方向」:节流 150ms,期间忽略所有中间 scroll 事件
- 加距离阈值:连续向下滚动 ≥ 5px 才触发隐藏,避免抖动干扰
- 优先监听
wheel事件(比scroll更及时),统一用event.deltaY > 0表示向下(Chrome/Firefox/Safari 一致)
transform 还是 top?必须用 transform
top 触发 layout,动画卡顿明显;transform: translateY() 走合成层,性能好得多。但有两个硬前提:
- 导航栏必须是
position: fixed,且初始top: 0,再用transform: translateY(-100%)隐藏——不能只写top: -60px - 父容器不能有
overflow: hidden或其他transform,否则会截断移出区域 - 过渡动画用
transition: transform 0.3s cubic-bezier(0.22, 0.61, 0.36, 1),避免生硬弹跳
移动端 touch 滚动必须单独处理
iOS Safari 和 Android Chrome 在 overscroll 回弹阶段默认不触发 scroll,纯靠它在手机上基本不可靠。
立即学习“前端免费学习笔记(深入)”;
- 必须同时监听
touchstart(记下pageY)、touchmove(计算偏移)、touchend(判定方向) -
touchmove中慎用event.preventDefault()——只在你明确要拦截滚动时加,否则页面卡死 - 更稳妥的判断方式:用
getBoundingClientRect().top检查导航栏是否已完全移出视口,而非只信滚动方向
软键盘弹出会把 input 顶到隐藏栏下面
导航栏用 transform 移出屏幕,DOM 仍存在。iOS 键盘弹出时,整个页面被上推,原本在底部的 <input> 就会跑到隐藏的导航栏下方,用户看不见自己输入的内容。
- 监听
focus事件 +window.visualViewport?.height缩小,检测软键盘弹出,强制显示导航栏:element.style.transform = 'translateY(0)' - 给
<input>加scrollIntoView({ behavior: 'smooth', block: 'nearest' }),避免手动算偏移 - 微信 WebView 中需 UA 判断兜底,因
visualViewport支持不一
真正难的不是隐藏动作本身,而是滚动方向判断的鲁棒性、移动端 touch 与 scroll 的混合响应、以及软键盘这种动态视口变化下的状态同步——这三处不处理,用户一眼就能看出“假隐藏”。


















