Live 4-Header SnapEagerness Comparison
All four headers are active simultaneously! Scroll to see how different snapEagerness values behave in real-time.
๐ก How to test: Scroll at different speeds and directions. Watch how each header responds to your scrolling. The higher the snapEagerness value, the more "eager" the header is to snap into position.
๐ค The Story of the "Visual Gap"
Natural Sticky works by switching between relative and
sticky positioning at the perfect moment. But finding
that "perfect moment" is harder than it looks.
Act 1: The Perfect World
Imagine a header that is 100px tall, positioned just above the viewport (at -100px). In a perfect world, the user scrolls at a constant speed of 50px per frame.
- Frame 1: Position is -100px. Hidden.
- Frame 2: Position is -50px. Half visible.
- Frame 3: Position is 0px. Perfect! We switch to sticky mode.
Act 2: The Conflict (Overshooting)
But users don't scroll perfectly. What if they scroll faster, say at 60px per frame?
- Frame 1: Position is -100px. Hidden.
- Frame 2: Position is -40px. Mostly visible.
- Frame 3: Position is +20px. Oops! We wanted 0px, but we're already 20px down. That 20px space is a Visual Gap.
Act 3: The Prediction (SnapEagerness)
To fix this, we decided to look into the future. We calculate where the header will be in the next frame.
- Frame 2: Position is -40px. We predict next frame will be +20px.
- Decision: "It's going to overshoot! Switch to sticky mode NOW."
- Result: The header sticks at 0px before the gap can happen.
This is what snapEagerness controls: how far into the
future we look.
Act 4: The Plot Twist (Acceleration)
But what if the user accelerates?
- Frame 1: Position is -100px. Speed is 50px per frame. We predict next frame is fine.
- Frame 2: Position is -50px. We predict next frame will be 0px, nothing to worry about. But... User suddenly flicks their finger! Speed jumps to 60px per frame.
- Result: Next frame the position will be at 10px and not 0px. Our prediction was wrong. We overshoot again.
We could try to predict acceleration (calculating the derivative of speed), or even the rate of change of acceleration (jerk). But human input is unpredictable. A user might flick their finger at any moment.
Act 5: The Resolution (Deceleration)
We realized we were fighting the wrong battle. Scrolling has two phases:
- Acceleration Phase: Driven by user input (finger on screen). Unpredictable.
- Deceleration Phase: Driven by browser physics (inertia). Highly predictable.
The Solution: We simply wait. We keep the header hidden during the chaotic acceleration phase. We only engage our effect when the browser takes over and starts the smooth, predictable deceleration phase.
By combining Deceleration Detection with SnapEagerness, we get the best of both worlds: natural movement when possible, and gap prevention when necessary.
๐ What to Observe While Scrolling
1. Natural Movement (0.0) - Green Header
This header moves exactly with your scroll speed, providing the most intuitive experience. Notice how it feels completely connected to your scrolling motion.
- Pros: Most natural and intuitive feel
- Cons: May occasionally show small gaps on very fast scrolling
- Best for: Content-focused sites, reading experiences
2. Balanced Default (1.0) - Blue Header
The default value provides a sweet spot between natural movement and gap prevention. It predicts one scroll step ahead for smoother transitions.
- Pros: Good balance of natural feel and reliability
- Cons: Very subtle snapping might be noticeable to sensitive users
- Best for: Most general-purpose applications
3. Eager Prevention (2.0) - Orange Header
More aggressive gap prevention that predicts two scroll steps ahead. Notice the more pronounced snapping behavior.
- Pros: Virtually eliminates visual gaps
- Cons: More noticeable artificial snapping
- Best for: Complex interfaces where gaps cause layout issues
4. Magnetic Effect (3.0) - Red Header
Creates an intentional "magnetic" attraction to the top edge. The snapping becomes a deliberate part of the design language.
- Pros: Completely predictable, no gaps, distinctive behavior
- Cons: Least natural movement
- Best for: Gaming interfaces, when snapping is desired as a feature
๐งช Try These Tests
Slow Scrolling: All headers should feel natural and smooth.
Fast Scrolling: Notice how higher values prevent gaps but feel less natural.
Direction Changes: Quickly reverse scroll direction and observe how each header responds.
Momentum Scrolling: On mobile/trackpad, try flick scrolling to see behavior during deceleration.
๐ฏ Making Your Choice
The right snapEagerness value depends on your specific use case:
Choose 0.0-1.0 when:
- Natural movement is your top priority
- Building content-focused or reading interfaces
- Users typically scroll at moderate speeds
- You want the least distracting behavior possible
Choose 1.5-2.5 when:
- You have complex header layouts that can't show gaps
- Building mobile-first experiences (touch scrolling is often faster)
- Visual consistency is more important than naturalness
- You have animations or transitions that need reliable positioning
Choose 3.0+ when:
- Snapping behavior aligns with your design language
- Building gaming or highly interactive interfaces
- You want the header behavior to feel intentional and distinctive
- Zero tolerance for any visual gaps or inconsistencies
๐ Implementation
Setting snapEagerness is simple:
// Natural movement
naturalStickyTop(element, { snapEagerness: 0.0 });
// Balanced default (same as omitting the parameter)
naturalStickyTop(element, { snapEagerness: 1.0 });
// Eager gap prevention
naturalStickyTop(element, { snapEagerness: 2.0 });
// Magnetic effect
naturalStickyTop(element, { snapEagerness: 3.0 });
Keep scrolling to continue testing all four behaviors simultaneously!
This direct comparison eliminates the guesswork - you can immediately see and feel the differences between each setting.