I’ve got a navigation component that consists of a skinny banner (that should hide on toward scroll) and a main-nav that should then stick to top & and shrink.
I’ve followed the popular answer on using Intersection Observer:
Event to detect when position:sticky is triggered
But the issue with that solution is that my child elements (flex) cause a flicker when going between the hidden and shown sticky banner. I can’t remove those child elements for obvious reasons so instead I’m opting for a position: fixed
on the main-nav
with a top: 40px
. This means the skinny-banner scrolls away as desired, but I need help getting the scrollbar position with Javascript, and then adding a class like (.isSticky
when the skinny-banner is no longer there to ensure the main-nav sticks to the top).
.isSticky {
top: 0;
height: 66px;
}
body {
margin: 0;
height: 200vh;
}
.skinny-banner{
background: lightblue;
height: 40px;
display: flex;
}
.nav-menu {
display: flex;
}
.sticky-nav{
position: fixed;
top: 40px;
background: salmon;
transition: .1s;
}
/* styles for when the header is in sticky mode */
.sticky-nav.isSticky{
top: 0;
height: 66px;
}
<header>
<div class="skinny-banner">Skinny banner that on scroll down disapears.</div>
<div class="sticky-nav">Sticky Header that on scroll down sticks to top and shrinks in height when stuck</div>
</header>
I’m hoping to use a vanilla JS, HTML & CSS solution & want to maintain the HTML structure with a wrapping container with the skinny-banner and nav-menu as children.
3
Answers
It seems easier to set up a JavaScript listening to the scroll event on the window and updating the
isSticky
class accordingly based on the scroll position.I also removed the transition, in case it participates in the flicker you see.
To make sure the red banner
sticky-nav
should stick to the top even when scrolling up, theisSticky
class is added to the wrapper element as soon as the user scrolls past the height of the skinny-banner
, making thesticky-nav
stick to the top regardless of the scroll direction.Thank you for sharing your experience and insights! Please try out the following solution that might be helpful.
The reason for
.sticky-nav
fails to get sticky is because it is inside of the<header>
element. That element has a defaultdisplay: block
according to w3school. So it will block the sticky behavior for its child elements (includeposition: sticky
). To get this done, you should set thedisplay: initial
for the<header>
element.You can also detect when the element gets sticky with the value of
.offsetTop
. The value will change if the element gets sticky. But, before you should specifyposition: sticky
andtop: 0
for.sticky-nav
.