CSS scroll-margin-top Property

Sets the margin offset at the top of an element when it is scrolled into view, preventing it from being tucked under sticky headers.

selector { scroll-margin-top: value; }
<length> Defines a fixed distance from the top edge of the scroll port using units like px, em, or rem.
inherit Takes the scroll-margin-top value from its parent element.
initial Sets the property to its default value of 0.
revert Resets the property to the user agent's default styling.
unset Resets the property to its inherited value if it inherits, or to its initial value otherwise.

Code Examples

A basic example showing how to prevent a sticky header from overlapping a section when using an anchor link jump.

<style>header { position: sticky; top: 0; height: 60px; background: #333333; color: #ffffff; padding: 10px; } section { scroll-margin-top: 80px; padding: 20px; border-bottom: 1px solid #cccccc; height: 600px; }</style><header>Sticky Navigation</header><nav><a href="#tips">Jump to Tips</a></nav><section id="intro"><h1>Intro</h1></section><section id="tips"><h1>Pro Tips Section</h1><p>The browser scrolled here and left room for the header.</p></section>

An advanced example using JavaScript to calculate a dynamic offset based on a header's height and updating a CSS variable for the scroll margin.

<style>:root { --dynamic-offset: 0px; } .content-block { scroll-margin-top: var(--dynamic-offset); padding: 50px; border: 2px solid #006699; margin-bottom: 20px; }</style><div id="floating-ui" style="position: fixed; top: 0; width: 100%; height: 100px; background: #eeeeee; border-bottom: 2px solid #000000;">Dynamic UI Header (100px)</div><div style="margin-top: 120px;"><a href="#target-box">Scroll to Target</a><div style="height: 1000px;">Scrolling Space...</div><div id="target-box" class="content-block"><h2>I am the target</h2></div></div><script>const ui = document.getElementById("floating-ui"); document.documentElement.style.setProperty("--dynamic-offset", (ui.offsetHeight + 20) + "px");</script>

Pro Tip

You can use a CSS variable to manage your layout heights globally. Define a variable like --nav-height in your :root and use scroll-margin-top: var(--nav-height); on all your sections. If you ever decide to make your header taller or shorter, you only have to change one value in your CSS to update the scroll behavior for the entire site.

Deep Dive

Imagine your webpage is a map and the scroll position is a GPS coordinate. By default, when a user clicks an anchor link, the browser slams the target element right against the top edge of the viewport. If you have a sticky navigation bar, it acts like a giant sticker on your screen that covers up the very content your user wanted to see. Think of scroll-margin-top as a landing pad or a buffer zone. It tells the browser to stop the scroll operation a specific distance before it actually hits the element. It is important to note that this property does not affect the actual layout or position of the element in the document flow; it only influences the snap position or the landing spot during a scroll event.

Best Practices

Always apply this property to the child elements that are targets of anchor links, rather than the container. To keep your code clean, set the value to match the exact height of your sticky or fixed header. This ensures that when a user jumps to a section, the heading is fully visible and not obscured by your navigation menu.

Common Pitfalls

A frequent mistake is confusing this with scroll-padding-top. While they achieve similar visual results, scroll-padding is applied to the parent scroll container, while scroll-margin is applied to the individual child elements. Also, remember that this property does not accept percentage values; you must use fixed length units like px or rem.

Accessibility

This property is a win for accessibility. It ensures that keyboard users who navigate via skip links or anchor tags can actually see the content they just focused on, rather than having it hidden behind a fixed header, which can be disorienting and frustrating.

Dev Data Table: scroll-margin-top property

default 0
animatable yes
inherited no
experimental no
year_intro 2018
year_standard 2019
js_syntax_1 element.style.scrollMarginTop = "50px";
js_syntax_2 element.style.setProperty("scroll-margin-top", "50px");
js_note Use this property in JavaScript to dynamically adjust scroll offsets when your UI headers or floating elements change height at runtime.
browsers { "Chrome": 69, "Edge": 79, "Firefox": 68, "Safari": 14.1, "Opera": 56, "Chrome Android": 69, "Safari on iOS": 14.5, "Samsung Internet": 10.1, "Opera Mobile": 48 }
results render here...