Welcome to little lamb

CSS-only fixed header & proper anchor positions

Posted

Possibly you know the drill, if you've ever wanted to make something like a fixed header in CSS - which usually it's easy enough with a position: fixed; - then you're anchors are all wrong.

By wrong I mean whenever linking into one on the page, the browser will place it on top of the window, as one might expect, only it does so without taking into account that fixed header of yours, and so the anchor gets positioned/scrolled right behind it, which ain't so nice.

Plenty of such issues do exist on the interwebs, with solutions that commonly end with using negative margin and/or padding. But there's much simpler !

The first thing I'll talk about is how we fixed our header. Now it doesn't really matter for the solution we'll talk about, it works with a fixed position just as well, but...

Ouh, that's sticky

Did you know about the position: sticky; option ? Because I sure didn't (but I've been basically AFK for the last few years, and also do not really follow HTML/CSS evolution much. Really the later part, cause I think this has been a thing for a while now...), and it's pretty neat.

So for a fixed header a fixed position might be just good. But a sticky position can be useful in other situations, such as not a page-wide but a section-wide "fixed" - or rather, sticky - banner of sorts, or to make it "fixed" but not always.

Indeed, the sticky element will be positioned as usual, treated as relatively positioned, until its containing block crosses whatever threshold you specified, e.g. setting its top value.

Then, it gets "stuck" and will refuse to move, effectively becoming a fixed-positioned element for now. Although, should it meet the opposite edge of its containing block, it'll get "unstuck".

So pretty much if you happen to (and can, based on the page layout) scroll past the end of whatever section of the document it belongs, the whole thing (with the fixed/sticky element in it) will scroll by.

Which also means you can get it to start to scroll, but then stop and remain fixed/stuck. Which is, for example, how the fixed - or rather, sticky - banner on top of this site works : it starts scrolling with the page, only to get stuck so the navigation part remains visible at all times.

You can achieve such behavior simply with something like the following :

1
2
3
4
cssheader {
  position: sticky;
  top: -42px;
}

About those anchor positions ?!

Right, back on topic. So yeah, one major downside of having a fixed header on top of your page, as mentioned earlier, is that any link within the page won't get scrolled right as it should, but will end up hidden behind said fixed (or sticky) header.

Now you can forget about dealing with negative margin and/or padding, because there does exist a native CSS property made just for that : scroll-margin

It allows to do just what you'd expect, and what is needed in our case : add a scrolling margin to an element. Of course it comes in all four flavors you'd except : top, right, bottom and left.

Obviously in our case the top one is the one we're interested in, and we can use use along side another nice little feature I only recently found out about : the target pseudo-class.

What is an anchor if not a :target ?

This lovely little pseudo-class will match whatever element is being "linked to" - or targeted - by its id. Which is pretty much exactly what happens whenever you link to a point in your page.

So let's say you have a fixed header of 100px that remains stuck on top of your page, and you want your anchors to be visible whenever linked to ? That's seems pretty reasonable, won't you say ?

1
2
3
css:target {
  scroll-margin-top: 100px;
}

Yep, that's about all it needs. (You can add a little more if you want space between your anchor and the header, of course.) Ain't that a thing ?

Alright, that's all for now. I'll just mention in passing another CSS thing that I only recently discovered, despite also being around for some time, just like what we've seen today, and just like them being therefore nicely supported all over the place : the grid placement.

If you ever want to "split" your page into rows and/or columns, to have a header and a footer, or a column on the side for navigation links, table of contents or whatever, there are certainly an infinite number of ways to achieve such a thing. I'll recommend you to have a look at the grid layout, which handles all that quite easily and can simplify things a lot.

Anyways, that's all for me for now. Have fun!