Scrollbar-Aware 100vw with scrollbar-gutter: stable

Full-width elements without horizontal scrollbar overflow

Using 100vw on a desktop with a classic scrollbar always overflowed the page horizontally. The fix used to be JavaScript that measured the scrollbar and exposed its width as a custom property. CSS now solves this when the root commits to a stable scrollbar gutter.

Old way 8 lines
const sbw = window      .innerWidth - document   .documentElement.clientWidth;document.documentElement     .style.setProperty(           '--scrollbar', sbw + 'px');window.addEventListener( 'resize', () =>  {  const w = window     .innerWidth - document   .documentElement.clientWidth;  document.documentElement   .style.setProperty(         '--scrollbar', w + 'px');});
Modern
3 lines
html   {  scrollbar-gutter: stable; }.full-bleed   {  width: 100vw;  margin-inline: calc(50% - 50vw);}
Limited availability 65% global usage

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Not ready for production without a fallback.

145+
145+
100vw now matches the actual usable viewport width
html { scrollbar-gutter: stable }
100vw element (no overflow)
previously: overflow caused by scrollbar width
100vw subtracts the scrollbar

No measurement script

No window.innerWidth versus documentElement.clientWidth subtraction. No resize listener to keep a --scrollbar custom property in sync.

Triggered by scrollbar-gutter

The browser only subtracts when the scrollbar (or its reserved gutter) is guaranteed to be visible. Set scrollbar-gutter: stable on the root, or use overflow-y: scroll, and 100vw adjusts.

Applies to every variant

All viewport units track this. vw, svw, lvw, dvw all subtract the vertical scrollbar. vh and its variants subtract a horizontal scrollbar when forced.

Lines Saved
8 → 3
No JS measurement
Old Approach
JS scrollbar math
innerWidth - clientWidth
Modern Approach
scrollbar-gutter: stable
vw becomes scrollbar-aware

How it works

Set width: 100vw on an element with a classic vertical scrollbar present and you get a horizontal scrollbar. 100vw historically included the scrollbar in its width, so the element was always wider than the usable viewport. The workaround was JavaScript: subtract document.documentElement.clientWidth from window.innerWidth, expose the difference as a custom property, and use calc(100vw - var(--scrollbar)) everywhere.

Chrome now subtracts the scrollbar from viewport units when the root commits to reserving space for one. Add scrollbar-gutter: stable (or overflow-y: scroll) to the html element and 100vw becomes the width of the actual usable viewport. The same rule applies to vh with a horizontal scrollbar. The advantage of scrollbar-gutter over overflow-y: scroll: a scrollbar only draws when the page actually needs one.

ESC