Nicer Anchors

If you've ever written an FAQ or long-body-format web page, you'll undoubtedly have used anchor tags for deep-linking.

Generally we use href="much-link.htm" every day for hyperlinks to other pages, but we'll also link to headings or sections of our own body when it is called for; href="#wow".

There's a small aesthetic issue when using href="#so-anchor" though, and that's to do with the way browsers handle it; they move the top of the element exactly to the top of the viewport — as demonstrated below.

See the Pen heading-anchor-bad by Simon Goellner (@simeydotme) on CodePen.

You wouldn't put your header against the top of the page normally, so why do it when deep-linking?

It's also exacerbated or just unusable if we have any kind of fixed-header. So the general way people try to get around this aesthetic issue is by using javascript to smooth-scroll the element in to view and then scroll up a little bit more with a calculation.

I propose a method without any javascript, see below;

See the Pen heading-anchor-gooder by Simon Goellner (@simeydotme) on CodePen.


How?

We'll use pseudo-elements and pseudo-classes to apply a "padding" above the currently targetted anchor.

Firstly let's make use of the :target pseudo-class which allows us to style any element which has the same href="#" as the hash in the url. It's available from IE9 as shown on caniuse

.anchor:target {}

We then use this to append a pseudo-element to the anchor which will give us a set amount of space above the anchor:

.anchor:target:before {
    /* first we need to give it layout */
    content: "";
    display: block;

    /* then dimensions */
    height: 1em;
    margin-top: -1em;
    width: 0;
}

Now the 1em value is up to you, I find it works nice as it's always proprtional to the heading size. We also use width: 0; so that the browser doesn't draw a nasty outline around the pseudo-element when we're focussed on it. Finally margin-top: 1em; is used to remove the extra whitespace created above the heading.


such attract.

Why not go one step further and inspect the code for this blog's headings — you'll see the :target being used to paint a fancy icon and change the colour of headings. Try it out by clicking here.