Down the rabbithole

CSS tricks: respecting spacing in hash navigation

When implementing a hash-based navigation, it’s not trivial to control the actual starting position of headings. This could cause headings to be cut off or hidden below your floating navigation. I’ll show you two ways to fix that.

But first: what’s the problem?

When using hash navigation, browsers take advantage of the id attribute to find and jump to elements on the page. This is very useful in long documents, when you’d like to enable visitors to jump to sections further down. So, for instance, you can have a <h2 id="monstera">, and upon clicking a link <a href="#monstera">, users are taken to the respective section. This works with any kind of HTML element – just make sure ids are unique.

But the problem is where exactly it jumps to: right where content starts.

Consider this example. As you navigate back and forth between the two sections, the title will be hidden by the floating header. As you can see in the screenshot below, the text inside h2#monstera is right at the document’s top, with a lower z-index than the header’s, and it seemingly doesn’t respect the margin. Except, it does — margin is just not part of the content.[1]

So, how could we make that space part of the content?

Simplest solution: change margin to padding

Pretty easy: change your element’s margin to 0, and add some padding. Of course, you can offset the extra padding with a negative margin, in case you want less spacing between sections.

h2 {
  margin: -1em 0 0;
  padding: 1.8em 0 .5em;
}

Here’s the previous demo, updated.

Alternative solution: ::before

If you don’t want to change padding for some reason, you can use a the ::before pseudo-element as well. It will insert a node as the first child of our h2, and as such, is part of the box. You can control its height as below.

h2 {
  margin-top: -1em;
}

h2::before {
  content: '';
  display: block;
  height: 1.8em;
}

Here’s the demo for this version.


  1. To understand how this works, I recommend reading about the box model. ↩︎