Offset Anchors

Visually offset anchors when using fixed navbar
Tagged: cssTuesday, March 19, 2019

The Problem with Anchors and Fixed Headers

I have a site that has a typical fixed/static header at the top, which is a pretty common design pattern. However if you use anchor links or a library like Anchor.js you will hit an issue with the fixed header is visually blocking your anchor targets. By default a browser will put the anchor target to the top of the web browsers viewport.

Solutions to Anchor targets and a Fixed Header

My first (but wrong) solution was to use a javascript library such as jquery.localScroll which seemed to fix the issue. It basically highjacks anchor navigation and you can define an offset equal to you header. This way anchors appear just below your fixed header.

Later however during an Accessibility audit, we found this causes issues with screen readers and keyboard navigation, especially when they use "skip links" to navigate directly to the main content. The javascript highjack, causes the keyboard focus to be reset at the top of the page, totally defeating the point of skip links.

A CSS only Solution to Anchors and Fixed Headers

In modern browsers you can use the following which basically moves the element up and back down so that when the browser scrolls to the anchor (its default behavior) and places it at the top, its offset enough where it does not appear under you fixed header.

pointer-events: none; is needed because technically your element is higher on the page, and if a link was just above a header, your header would block the click to that link. So this removes the elements "click-ability".

:target {
  border-bottom: 3px solid yellow;
  padding-top: 80px; /* the height of your header */
  margin-top: -80px; /* the height of your header */
  display: inline-block;
  pointer-events: none;
}

Here is my SASS/SCSS solution for a site that was using the Anchor.js library.

@for $i from 2 through 6 {
  h#{$i}:target {
    border-bottom: 3px solid yellow;
    padding-top: 80px; //the height of your header
    margin-top: -80px; //the height of your header
    display: inline-block;
    pointer-events: none;
  }
}