CSS scroll-margin-block-start Property

This property sets the margin at the start of the block dimension for a scroll snap area, providing an offset between the element and the scroll container's edge.

selector { scroll-margin-block-start: <length>; }
<length> Specifies a fixed distance using units like px, em, or rem.

Code Examples

A basic scroll-snap example where each section stops 50 pixels below the top of the container.

<style>
  .container {
    height: 300px;
    overflow-y: scroll;
    scroll-snap-type: y mandatory;
    border: 2px solid #333333;
  }
  section {
    height: 300px;
    scroll-snap-align: start;
    /* This creates a 50px gap at the top when snapping */
    scroll-margin-block-start: 50px;
  }
  .one { background: #ff5555; }
  .two { background: #55ff55; }
</style>
<div class="container">
  <section class="one">Section 1</section>
  <section class="two">Section 2</section>
</div>

A semantic example using a fixed header and a dynamic offset calculation, demonstrating how the property works with both anchor links and JavaScript scroll methods.

<style>
  :root {
    --nav-height: 60px;
  }
  header {
    position: fixed;
    top: 0;
    height: var(--nav-height);
    width: 100%;
    background: #222222;
    color: #ffffff;
    z-index: 10;
  }
  article {
    margin-top: var(--nav-height);
  }
  h2 {
    /* Offset the heading so it is not hidden under the fixed header */
    scroll-margin-block-start: calc(var(--nav-height) + 20px);
    background: #eeeeee;
  }
</style>
<header>Fixed Navigation Bar</header>
<nav>
  <a href="#topic1">Go to Topic 1</a>
</nav>
<article>
  <div style="height: 1000px;">Scroll down or click the link...</div>
  <h2 id="topic1">Topic 1</h2>
  <p>Content for topic 1 starts here.</p>
  <button onclick="scrollToTopic()">JS Scroll</button>
</article>
<script>
function scrollToTopic() {
  document.getElementById("topic1").scrollIntoView({ behavior: "smooth" });
}
</script>

Pro Tip

You can use CSS variables to manage this offset globally. If your header height changes at different breakpoints, update a single variable like --header-height, and use scroll-margin-block-start: var(--header-height); on all your section headings. This keeps your code clean and your offsets consistent across the entire application.

Deep Dive

Think of this property as a logical buffer. In a standard top-to-bottom layout, block-start refers to the top. When a user navigates to an element via an anchor link or scroll snapping, the browser usually puts that element flush against the top of the viewport. This property tells the browser to leave a specific amount of 'breathing room' instead. Because it is a logical property, it automatically adapts to different writing modes. If the text direction changes to vertical, the offset moves from the top to the side without you having to rewrite your CSS. It defines the snap area that is used for snapping the visual viewport to the element.

Best Practices

Use this property whenever you have a fixed header on your website. Without it, anchor links will jump to a section and the header will cover the first few lines of text. By setting this value to match the height of your header, you ensure the content is perfectly visible. Always prefer logical properties like this over physical ones like scroll-margin-top to ensure your site is ready for internationalization and different text orientations.

Common Pitfalls

A common mistake is applying this to the scroll container itself. It must be applied to the child element that you are scrolling to. Also, keep in mind that this margin does not affect the actual layout or spacing of elements on the page; it only changes the behavior of the scroll position when snapping or navigating to that element.

Accessibility

This property is a big win for accessibility. When keyboard users tab through links or use a table of contents, jumping to a section that is partially obscured by a fixed menu can be disorienting. Providing a clear offset ensures that the focused content is fully within the visible viewport, making the experience much smoother for users with visual or cognitive impairments.

Dev Data Table: scroll-margin-block-start property

default 0
animatable no
inherited no
experimental no
year_intro 2018
year_standard 2019
js_syntax_1 element.style.scrollMarginBlockStart = "20px";
js_syntax_2 element.style.setProperty("scroll-margin-block-start", "20px");
js_note When using JavaScript, the property follows the standard camelCase convention for logical properties unless you are using the setProperty method.
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...