On Sticky Headers and Internal Links

Time for something geeky.

Suppose, you got yourself a website, which just has to have a header that stays on the top of the page. That’s easy. Add some position: fixed to your stylesheet, and Håkon‘s your uncle.

The thing is, there might be some content following your header. And in that content, the might be some links that point to places further down the page. And if you happen to click on one of those links, the browser goes to that point in the page. Which then promptly disappears behind your fixed header. As it should.

This is not desirable.

Or so they told me when just such a header was introduced on a certain website I happen to work on quite a bit. They also told me I had to find a solution. I came across a perfectly nifty solution using the :before pseudo-element. The idea is that you add a pseudo-element to your targeted element with your desired offset height—say, your header is 50px high, you make it at least that high—and then compensate with a negative top-margin.

The only problem was that the original solution used classes or id’s to apply the pseudo-elements to. In my case, that wasn’t going to work. There were a lot of different elements with different classes that could be targeted. So I improved it a little bit by applying the :before pseudo-element to the :target pseudo-class, like so:

:target:before {
   content: ''; /* a pseudo-element needs content. we'll leave it empty. */
   display: block;
   height: 75px; /* 50px for the header, another 25 to make it pretty. */
   margin-top: -75px; /* and we pull it back up. */

I’ve put the whole shebang in a jsfiddle for you to fiddle with.

This works in all modern browsers I tested it in (Firefox, Opera. Chrome and IE9 on Windows, Firefox and Chromium on Ubuntu), and fails horribly in IE8 and earlier. It also didn’t work in all the places where it should have worked, but that had more to do with the way the content was edited.