CSS scroll-padding-block-start Property
This property defines the offset distance between the start edge of the scrollport and the target element during a scroll-snap operation.
| auto | The browser determines the appropriate offset, which is typically zero. |
| <length> | Specifies a fixed distance from the start edge using units like px, em, or rem. |
| <percentage> | Defines the offset as a percentage of the scroll container's size in the block dimension. |
Code Examples
A basic scroll-snap container where each section stops 50 pixels from the top edge to simulate space for a header.
.scroll-container {
width: 300px;
height: 300px;
overflow-y: scroll;
scroll-snap-type: y mandatory;
scroll-padding-block-start: 50px;
border: 2px solid #333333;
}
.child-section {
height: 300px;
scroll-snap-align: start;
background-color: #f0f0f0;
border-bottom: 1px solid #cccccc;
}An advanced approach using CSS variables and JavaScript to ensure the scroll-padding always matches the dynamic height of a fixed header.
<style>
:root {
--header-height: 80px;
}
body {
scroll-padding-block-start: var(--header-height);
font-family: sans-serif;
}
header {
position: fixed;
top: 0;
width: 100%;
height: var(--header-height);
background: #222222;
color: #ffffff;
}
</style>
<script>
window.addEventListener("resize", () => {
const header = document.querySelector("header");
const height = header.offsetHeight + "px";
document.documentElement.style.setProperty("--header-height", height);
});
</script>Pro Tip
Instead of using old-school hacks like invisible 'anchor' elements with negative top positions, use this property on your 'html' or 'body' tag. It keeps your HTML clean and handles different screen sizes or dynamic header heights much more elegantly with CSS variables.
Deep Dive
Think of this property as a 'stand-off' distance for your scroll container. When a user clicks a link that jumps to a specific ID on your page, the browser usually puts that element right at the very top of the viewport. If you have a sticky header, your content gets tucked underneath it like a letter in an envelope. This property tells the container to stop the scroll a bit earlier, leaving a buffer zone. Because it is a logical property, 'block-start' refers to the top edge in a standard horizontal layout, but it will automatically adjust if the writing mode is changed to vertical. It acts as part of the 'scroll-padding' shorthand, specifically targeting the start of the block axis.
Best Practices
Apply this property to the parent scroll container rather than the individual child elements. It is most effective when you have a fixed or sticky navigation bar that persists at the top of the screen. By setting this value to match the height of your navigation bar, you ensure that 'jump links' or 'scroll-snapping' don't hide the headings or content your users are trying to see.
Common Pitfalls
The most common mistake is trying to apply this to the target child element; it must be set on the scroll container itself to work. Also, remember that it only affects the 'snapping' or 'scrolling to' behavior; it does not add actual visual padding or space to the layout of the elements inside. If your container doesn't have 'overflow' set to 'scroll' or 'auto', this property won't do anything.
Accessibility
This is a big win for accessibility. When keyboard users navigate via links that jump to different sections of a page, they need to see where they've landed. If the focus target is hidden behind a sticky menu, the user is lost. Using this property ensures the focused content is always visible in the 'scrollport' for all users.
Dev Data Table: scroll-padding-block-start property
| default | 0 |
| animatable | no |
| inherited | no |
| experimental | no |
| year_intro | 2018 |
| year_standard | 2019 |
| js_syntax_1 | element.style.scrollPaddingBlockStart = "20px"; |
| js_syntax_2 | element.style.setProperty("scroll-padding-block-start", "20px"); |
| js_note | When manipulating this property in JavaScript, remember that it is a logical property and its physical effect depends on the writing-mode and direction of the element. |
| 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 } |