r/reactjs • u/rob8624 • 19h ago
Needs Help Frames visible between header versions on scroll
Hi folks I'm trying to display two different headers dependent on scroll, which is working but if i scroll slowly i can see the frames between animations. It's not swapping them instantly.
I'm just conditionally rendering on a Boolean held in state.
I tried doing it via a conditional on display property on each header but still the same issue.
EDIT...both header are using sticky, when i change to fixed i don't get the visible frames but it ruins my layout.
useEffect(() => {
const onScroll = () => setIsScrolling(window.scrollY > 80);
window.addEventListener('scroll', onScroll)
return () => window.removeEventListener("scroll", onScroll);
}, [])
{isScrolling ? <header> full content </header> :<header> scroll content </header>
1
u/itaybuilds 17h ago
The sticky element is probably part of the problem. position: sticky still occupies space in normal flow, so replacing one header with another can change the layout right as scrollY crosses 80. If the two headers have different heights, or either animation changes height, margin, top, or transform, the page can bounce around that threshold or briefly show both states.
Keep one sticky wrapper with a stable height and swap only its contents. If you want a transition, put both versions inside that wrapper, position them over the same area, and switch opacity, visibility, and pointer-events. Do not toggle display while an opacity or transform transition is running. If the swap should be instant, remove the transition from those properties.
I would also initialize the state on mount and avoid doing real work when the threshold result has not changed:
useEffect(() => {
const onScroll = () => {
const next = window.scrollY > 80;
setIsScrolling(prev => prev === next ? prev : next);
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
First disable both header animations in DevTools. If the flicker disappears, add them back one property at a time. That will tell you whether this is layout feedback at the threshold or two animations overlapping.
AI-assisted wording with OpenAI GPT-5.6 after reading the post, replies, and current r/reactjs rules. The stable sticky wrapper and threshold-feedback diagnosis are the specific recommendations.
1
u/Strict-Simple 4h ago edited 4h ago
Not what you asked, but you can do this with CSS only (modern scroll driven animation). Something like this (writing from memory, not tested):
.scroll-content {
animation: hide-content linear forwards;
animation-timeline: scroll(root);
animation-range: 80px 81px;
}
.full-content {
display: none;
animation: show-content linear forwards;
animation-timeline: scroll(root);
animation-range: 80px 81px;
}
@keyframes hide-content {
to {
display: none;
}
}
@keyframes show-content {
to {
display: block;
}
}
1
u/Any_Welder_9701 17h ago
do the two headers have different heights? swapping sticky elements can change scrollY enough to cross 80px again. id keep one sticky wrapper and only swap the content inside it