Anchoring elements in scrollable areas
Tags: html, css, design
Published: 2022-08-31 05:13:11

---
title: Anchoring elements in scrollable areas
published: true
description: Using relative and absolute positioning to anchor elements within a scrollable parent.
tags: html, css, design
canonical_url: https://www.horuskol.net/blog/2022-04-13/relative-and-absolute-scrolling-blues/
---

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:

{% codepen https://codepen.io/HorusKol/pen/poLMXgX %}

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 vs absolute positioning

**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.

## Contain yourself

I reached out to the Perth Fenders community, who are some really awesome developers and designers. [One solution from Pete Barr][container solution] involves using some additional containers:

{% codepen https://codepen.io/HorusKol/pen/PoRMrGB %}

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.

## Getting sticky with it

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.

Similarly, `bottom: 0` will have it sit at the bottom until you scroll past where it would be in the flow.

{% codepen https://codepen.io/HorusKol/pen/ZExgdBY %}

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:

{% codepen https://codepen.io/HorusKol/pen/zYWgVZB %}

### Refinement

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!

{% codepen https://codepen.io/HorusKol/pen/dymxBWV %}

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.

## Side-scrolling adventure

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.

{% codepen https://codepen.io/HorusKol/pen/KKoOOaN %}

Because the `<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.

[container solution]: https://codepen.io/petebarr/pen/wvpeKgW/d88c80eb21950f0d0ec2ca7055ce5aa1
[tweet by Dries Vints]: https://twitter.com/driesvints/status/1513828038911401985