Scrollable sticky element

I don’t have a solution for this problem yet, but I’ll describe the problem:

When an element is made sticky (position: sticky;) it is pinned to its nearest scroll containing ancestor. However, if the sticky content is taller than the viewport of the scroll container, its excess content (what doesn’t fit within the viewport) is not visible until the end of the scroll container is reached.

A feature that I’ve had to implement a few times now is similar to a sticky element except that in the case described above, the sticky element scrolls with the container until the opposite edge is reached (the bottom when scrolling down) and is dragged along until the end of the scroll container is reached or the scroll direction is changed. If the scroll direction changes, the sticky element stays in place (as if it were absolutely positioned in the place where the scroll direction changed) until an edge is reached.

This pattern is sometimes used for document outline navigation kept to the side of a long document.

It would be great if this behavior was able to be implemented in CSS rather than relying on JavaScript. Every JS implementation relies on listening to scroll events which causes problems. If the scroll handler fires too often, it can slow down the page significantly. If the scroll handler is debounced, the sticky element could appear to lag behind the scrollable content and may overshoot the edge of the scroll container and have to jump back into place once the handler fires.

Maybe sticky-behavior: scroll; or something.

Would this not mean that the top of the sticky element would not be visible? Why is it better that the top is not visible than the bottom? I feel the top of an element is usually more important than the bottom.

If the sticky element scrolled immediately when the scroll direction changes, regardless of the direction, then that could be a solution for sticky elements that are taller than the viewport.

Here’s an old JSFiddle showing what I mean. This is a JQuery plugin of an implementation I made in 2013. Note the purple box scrolls with the page until it’s edges are visible.

Screen Shot 2021-11-02 at 12.09.24 PM

…after scrolling down…

Screen Shot 2021-11-02 at 12.09.32 PM

I’m not sure this is what you’re looking for, but I hope it helps. This is how I used to do sticky table of contents in the sidebar, constrained to viewport height and scrolling if too long (forked your jsfiddle):

CSS only.

Yes, then I understood correctly. So my question is, why is it more important that the bottom of the purple box is visible instead of the top? If the element is sticky, then its top is probably more important than its bottom. As a user, I would rather have the bottom cut off than the top.

I’m sure in some cases the top is more important. But I’d like the ability to make a sticky element scrollable for cases where discoverability of the bottom of the element is important. Or cases where the scroll container is infinite and so the bottom would never be reached and then the off-screen portion of the sticky element would never be revealed.

What do you think of my idea of having the element scroll as soon as the user changes scroll direction? So when scrolling down, the sticky element would scroll to its bottom edge and then stay there, but if the user started scrolling up, the element would immediately start scrolling to its top edge.

Yes, the sticky element scrolling (becoming un-stuck) when changing scroll direction is the behavior I want.

Ok, that sounds like a useful feature. (Sorry, I didn’t check the demo.) Browsers could even make it the default behavior.

1 Like

I ran a little poll on Twitter, where I used the terms lazy and eager scrolling to describe the different behaviors. Since there is interest for this feature, I suggest opening an issue in the w3c/csswg-drafts repo.

1 Like