Problem

Many websites use a sticky / fixed header (which usually includes the logo and a navigation menu) that is always at the top of the viewport (using position: sticky or position: fixed), even when the user scrolls the page.

While this may improve the user experience (since the navigation menu is always easily accessible), it can cause a problem when trying to auto-scroll to a particular element on the page.

The target element (to which we want to scroll) will be covered behind the sticky header.

This is because the sticky header “floats” on the page and its size is not taken into account.

By default, the target element will be snapped to the top of the page, and therefore will be hidden behind the sticky header that’s also right at the top of the page.

We will face this problem whether we use JavaScript or anchor links (e.g. id="form" in the element and #form as the link) to perform the auto-scrolling.

Solution

Fortunately, there’s an easy way to fix this using a single CSS property: scroll-padding-top.

This is a very useful and simple CSS property that is also well supported by the vast majority of browsers.

Let’s say we have a sticky header whose height is 70px.

We’ll simply add this CSS code:

html {
	scroll-padding-top: 70px;
}

This will add “invisible padding” to the main html element that will only be used when auto-scrolling is performed. As a result, the element will be placed not quite at the top of the page, but 70px from it, allowing it to appear right after the sticky header.

We may want to add a small gap so that the element has a few pixels of space from the header. To do this, we can simply adjust the value of scroll-padding-top. For example, use 80px to create a 10px space from a 70px sticky header.

Finally, if the height of the sticky header varies between mobile and desktop (say, 70px on mobile and 100px on desktop), we can change the scroll-padding-top value using media queries, similar to the following SCSS code:

html {
	scroll-padding-top: 70px;

	@media (min-width: $min-lg) {
		scroll-padding-top: 100px;
	}
}