loke.dev
Header image for Stop the Layout Jump

Stop the Layout Jump

Use the native scrollbar-gutter property to keep your UI perfectly aligned and prevent annoying horizontal shifts when content height fluctuates.

· 4 min read

You’re looking at a perfectly centered layout, and then you click a button that opens a modal or loads more content, and—*thwip*—the whole page shudders a few pixels to the right. It’s the digital equivalent of someone bumping your elbow while you’re trying to draw a straight line. It’s subtle, but once you notice it, you can’t unsee it.

The classic "Jank"

This happens because of how browsers handle the scrollbar. On most desktop operating systems (looking at you, Windows), the scrollbar occupies actual physical space. When your content is short, there’s no scrollbar. When your content gets long enough to overflow, the browser squeezes the viewport to make room for that 15-17px wide bar.

If your layout is centered, the "center" of the screen literally moves.

In the old days, we dealt with this using some pretty gross hacks. I remember writing stuff like this just to force the scrollbar to exist regardless of content height:

/* The "I give up" approach */
html {
  overflow-y: scroll;
}

It worked, but it looked terrible on short pages where a ghost scrollbar just sat there, taunting the user. Or, we’d try to do some hacky math with 100vw vs 100%, which usually ended in tears and weird horizontal overflow issues on mobile.

Meet scrollbar-gutter

CSS finally gave us a native way to fix this without the hacks. The scrollbar-gutter property tells the browser to reserve space for the scrollbar, even if it isn’t currently needed.

Here is the basic implementation:

html {
  scrollbar-gutter: stable;
}

By setting it to stable, you’re telling the browser: "Hey, keep that space on the side reserved. If a scrollbar appears, cool. If not, don't let the content expand into that territory."

The result? Your layout stays perfectly still. No jumps, no shudders, no shifting pixels.

Taking it a step further: both-edges

If you’re a perfectionist (and if you're reading a post about 15px layout shifts, you probably are), stable might leave your layout feeling a bit lopsided. Since the gutter is only on one side, your "centered" content is technically centered relative to the remaining space, not the whole window.

If you want absolute symmetry, you can use the both-edges keyword:

.container {
  scrollbar-gutter: stable both-edges;
  max-width: 800px;
  margin: 0 auto;
}

This adds the same gutter to the left side as well. It’s a bit of a niche use case, but for high-end marketing sites or portfolios where symmetry is everything, it's a lifesaver.

The "Overlay" Catch

Here is a bit of a reality check: scrollbar-gutter doesn't do anything on systems that use "overlay" scrollbars. Think macOS (with a trackpad) or mobile browsers.

On those devices, the scrollbar floats *on top* of the content. It doesn't take up space, so it doesn't cause a layout jump. In these cases, the browser ignores scrollbar-gutter because the "problem" it solves doesn't exist there.

You can check if a browser supports it with a simple feature query, though it’s safe to use as a progressive enhancement regardless:

@supports (scrollbar-gutter: stable) {
  html {
    scrollbar-gutter: stable;
  }
}

A practical example: The Modal Jump

The most common place I run into this is when opening a modal. Usually, you want to prevent the background from scrolling, so you do something like this in JavaScript:

// When modal opens
document.body.style.overflow = 'hidden';

// When modal closes
document.body.style.overflow = 'auto';

The moment overflow: hidden hits, the scrollbar vanishes, and the entire site behind the modal jumps to the right. It looks amateur.

If you have scrollbar-gutter: stable on your html or body tag, that jump disappears entirely. The scrollbar leaves, but the "gutter" stays.

/* Put this in your global CSS and forget about the jump forever */
html {
  scrollbar-gutter: stable;
}

Is there a downside?

The only real "downside" is that you have a constant empty strip on the right side of your page on Windows/Linux desktop browsers. But honestly? It's much less distracting than a UI that vibrates every time a dynamic element loads.

We've spent years fighting the browser's default behavior with complex calculations. scrollbar-gutter is one of those rare properties that solves a decade-old annoyance with a single line of code. Use it. Your users’ eyes will thank you.