position: sticky works on some mobile browsers now, so you can make a menu bar scroll with the page but then stick to the top of the viewport whenever the user scrolls past
In some cases a simple IntersectionObserver can do the trick, if the situation allows for sticking to a pixel or two outside its root container, rather than properly flush against. That way when it sits just beyond the edge, the observer fires and we're off and running.
const observer = new IntersectionObserver(
([e]) => e.target.toggleAttribute('stuck', e.intersectionRatio < 1),
{threshold: [1]}
);
observer.observe(document.querySelector('nav'));
Stick the element just out of its container with top: -2px, and then target via the stuck attribute...
nav {
background: magenta;
height: 80px;
position: sticky;
top: -2px;
}
nav[stuck] {
box-shadow: 0 0 16px black;
}
Example here: https://codepen.io/anon/pen/vqyQEK