scroll-margin
Sets the space left in front of the destination element when you jump to it, for example with an in-page link. Replaces the hack of shifting an empty anchor element so headings don't end up hidden under a fixed header.
Modern approach
Set the space you want in front of it on the destination element. The id goes right on the destination element, so you need neither an empty element nor a wrapper.
h2 {
scroll-margin-top: 80px;
}
<h2 id="contact">Contact</h2>Legacy approach
The heading was wrapped in a container, and an empty anchor element was absolutely positioned and shifted up by the header height. Since the id goes on the anchor, the heading’s layout stays the same, but you need an extra element and a wrapper just for the id.
.section {
position: relative;
}
.anchor {
position: absolute;
top: -80px;
}
<section class="section">
<a id="contact" class="anchor"></a>
<h2>Contact</h2>
</section>Things to watch when replacing
- It works when the scroll targets an element: in-page links, opening a URL with a
#, andscrollIntoView(). If you use scroll snapping, it also affects where scrolling stops. Otherwise it has no effect onscrollTo(), which takes coordinates. - You set it on each destination element. To define the header height in one place, you can set
scroll-padding-toponhtmlinstead.scroll-padding-tophas also worked in all browsers since April 2021. - If the header height changes with the viewport width, put the height in a custom property and use it for both the header and
scroll-margin-top.
Browser Support
Chrome
v69+2018-09-04Edge
v79+2020-01-15Safari
v14.1+2021-04-26Fallback
from v11scroll-snap-marginSafari (iOS)
v14.5+2021-04-26Fallback
from v11scroll-snap-marginFirefox
v90+2021-07-13