如何正确使用window.scrollY实现滚动超50px后固定头部导航
问题原因
- 初始状态将
direction默认值设为"up",页面首次加载就会匹配固定导航样式,导致导航直接置顶遮挡顶部提示条 - 滚动监听未设置50px触发阈值,页面只要产生滚动就会切换导航样式,和顶部提示条产生层级冲突
- 用普通变量存储
oldScrollY会在组件重渲染时被重置,容易出现滚动方向判断错误 - 试图通过调整z-index解决遮挡属于治标不治本,没有从定位逻辑上规避两个元素的重叠场景
修复实现
- 将
direction初始值设为null,页面加载初始阶段不挂载任何固定/透明导航的特殊类,导航保持默认文档流定位,自然排在顶部提示条下方,不会产生遮挡 - 用
useRef存储上一次滚动位置,避免组件重渲染导致变量值重置 - 在滚动监听逻辑中增加阈值判断:只有页面滚动高度超过50px时才执行滚动方向判断,滚动高度回到50px以内时清空方向状态,导航回归默认位置
- 类名绑定统一处理,避免多个属性同时设置产生样式冲突
import { useState, useEffect, useRef } from 'react'; const Navbar = () => { const [direction, setDirection] = useState(null); const lastScrollY = useRef(0); const handleScroll = () => { const currentScrollY = window.scrollY; // 未达滚动阈值时重置状态,导航回到默认静态位置 if (currentScrollY <= 50) { setDirection(null); lastScrollY.current = currentScrollY; return; } // 超过阈值后判断滚动方向 setDirection(currentScrollY > lastScrollY.current ? 'down' : 'up'); lastScrollY.current = currentScrollY; }; useEffect(() => { window.addEventListener('scroll', handleScroll, { passive: true }); return () => window.removeEventListener('scroll', handleScroll); }, []); // 拼接导航类名 const navClassName = [ styles.navbar, direction === 'up' ? styles.fixed_navbar : '', direction === 'down' ? styles.transparent__nav : '' ].filter(Boolean).join(' '); return ( <header className={navClassName}> {/* 导航内部内容 */} </header> ); };
样式配置说明
- 只需要给
styles.fixed_navbar设置z-index: 999即可,顶部白色提示条不需要调整z-index:滚动高度在50px以内时,导航是普通文档流元素,不会和提示条重叠;滚动高度超过50px后,顶部提示条已经被滚动到视口外,不存在提示条遮挡导航菜单、链接无法点击的问题 - 可以给导航加
transition: all 0.3s ease过渡属性,样式切换时更顺滑 - 如果需要向下滚动时完全隐藏导航,可以在
styles.transparent__nav中加transform: translateY(-100%),比单纯设置透明的交互体验更好
内容的提问来源于stack exchange,提问作者Julia Schafer
相关产品推荐
相关产品推荐

