The other day I wanted to place an element into a scrollable container that would stay anchored near the bottom of the container as the user scrolled the rest of the content.
I thought that you could do this with absolute positioning:
As you can see - the "anchored" bar still moves as the user scrolls, even though the bar starts where we want it to.
My mental model was wrong - I was thinking that the anchored item would be positioned relative to the bounding box around the scrollable content. It isn't.
The item starts positioned relative to the bounding box - but it will keep its position relative to the parent (which scrolls within the bounding box), so it scrolls, too.
To make better sense of this, think about what would happen if you set overflow to
visible instead of auto.
The absolutely positioned element in the container will be anchored to the container - but the content will continue on down. As you scroll the whole page down, the absolutely positioned element will keep its place relative to the rest of the content.
Relative positioning is used to place an element relative to where it would normally be in the flow if left alone.
Absolute positioning places an element relative to the top-left corner of the nearest parent that is not positioned statically. Static positioning is the default.
I reached out to the Perth Fenders community, who are some really awesome developers and designers. One solution from Pete Barr involves using some additional containers:
The only problem here is that the scrollbar is obscured slightly by the anchored element - though this could probably be resolved with a bit more refinement.
I also had a try at using
sticky positioning. This has been around for a few years, but only received broad support in early 2021 (Chrome and Edge were the holdouts).
If you have something with
position: sticky and
top: 0, it will appear as you scroll up with the rest of the content, but as you scroll past the sticky element it will now sit at the top.
bottom: 0 will have it sit at the bottom until you scroll past where it would be in the flow.
I anchor the element from the top of the container with
top: calc(100% - 3rem); to ensure it stays where I want it. Unfortunately, I couldn't position it relative to the bottom, because there might not be enough other content in the container to make sure it always stays anchored down there.
But this solution itself creates a problem - there is now a gap at the top of the content which was the same size as the anchored item.
We can fix this with a height fix:
The above code works for when there's one line of text in the anchored element - but what about when we don't know how much text will be in there? It would just overflow down out of the viewable area.
Absolute position to the rescue!
So, our zero-height anchored element is stuck to the bottom of the viewable area - and its contents are absolutely positioned relative to the anchored element, so it grows up the page and not down.
As I was about to write all this, I saw a tweet by Dries Vints describing a similar problem, but in the horizontal axis. He was looking to have a button or toolbar sit over on the top right of a preformatted code example.
<pre> element uses preformatted space, we need to insert the toolbar on a single line with not whitespace, otherwise the sample code will have a margin above and below.
Other than that, we can see that we've stuck the toolbar to the top right of the scrollable container, and in a way that would allow use to easily insert multiple buttons without having to change the positioning.