scrollbar-gutter: stable
The jump when a scrollbar arrives
this line shifts left every time the bar appears
this line does not move at all
CaveatThere is only a gutter to reserve where the browser draws a classic scrollbar that takes space. On overlay scrollbars, the default on macOS and on every phone, the property is a no-op and the demo above only shows a difference because it styles ::-webkit-scrollbar and so opts out of them. For the page itself the property belongs on html, not on body.
FallbackUnsupported browsers ignore the declaration and you are back to the shift you started with, which is a nudge rather than a break. The old fix, overflow-y: scroll on html, reserves the same width permanently and still works everywhere; the cost is a dead scrollbar track on every page too short to need one.
<html> <!-- the scroll container, not body -->
html { scrollbar-gutter: stable; }
/* symmetrical, so centred content stays centred */
.pane { scrollbar-gutter: stable both-edges; }
Published
Questions
How do I stop the page shifting when a scrollbar appears?
Reserve the space before it is needed with scrollbar-gutter: stable on the scroll container, which for a whole page means html rather than body. The layout is then the same width whether the content overflows or not.
Why is scrollbar-gutter: stable not working?
Most often because the platform uses overlay scrollbars, which float above the content and take no space, so there is no gutter to reserve. That is the default on macOS and on phones. Check too that the rule is on the element that actually scrolls.
What does both-edges do?
It reserves the same width on the opposite side as well, so content centred inside the box stays centred instead of sitting slightly off towards the scrollbar. Without it the gutter is reserved on one side only.