fix(nav): prevent thrashing by using fixed position always
The thrashing was caused by a layout shift feedback loop: switching between position sticky (takes up space) and position fixed (overlays) caused content to shift, triggering IntersectionObserver again. Fix: Always use position fixed so nav state changes are purely visual (transparency, borders, colors) without any layout shifts. Also removed unnecessary hysteresis code since the root cause is fixed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -580,7 +580,7 @@ export function AppNavBar({ variant = 'full', navSlot }: AppNavBarProps) {
|
||||
shadow: isTransparent ? 'none' : 'sm',
|
||||
borderBottom: isTransparent ? 'none' : '1px solid',
|
||||
borderColor: isTransparent ? 'transparent' : 'gray.200',
|
||||
position: isTransparent ? 'fixed' : 'sticky',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
|
||||
@@ -24,31 +24,17 @@ export function HeroAbacus() {
|
||||
},
|
||||
}
|
||||
|
||||
// Detect when hero scrolls out of view with hysteresis to prevent thrashing
|
||||
// Detect when hero scrolls out of view
|
||||
useEffect(() => {
|
||||
if (!heroRef.current) return
|
||||
|
||||
let currentlyVisible = true // Start as visible (hero starts at top)
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
// Use hysteresis: different thresholds for showing vs hiding
|
||||
// When scrolling down (becoming invisible): hide when < 10% visible
|
||||
// When scrolling up (becoming visible): show when > 30% visible
|
||||
const ratio = entry.intersectionRatio
|
||||
|
||||
if (currentlyVisible && ratio < 0.1) {
|
||||
// Was visible, now scrolled far enough to hide nav branding
|
||||
currentlyVisible = false
|
||||
setIsHeroVisible(false)
|
||||
} else if (!currentlyVisible && ratio > 0.3) {
|
||||
// Was hidden, now scrolled far enough to show nav branding
|
||||
currentlyVisible = true
|
||||
setIsHeroVisible(true)
|
||||
}
|
||||
// Hero is visible if more than 20% is in viewport
|
||||
setIsHeroVisible(entry.intersectionRatio > 0.2)
|
||||
},
|
||||
{
|
||||
threshold: [0, 0.1, 0.3, 0.5, 1],
|
||||
threshold: [0, 0.2, 0.5, 1],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user