Prevent unwanted Layout Shifts caused by Scrollbars with the scrollbar-gutter CSS property

A side-effect when showing scrollbars on the web is that the layout of the content might change depending on the type of scrollbar. The scrollbar-gutter CSS property —which will soon ship with Chromium — aims to give us developers more control over that.

Let’s take a look.

~

Table of Contents

  1. Classic vs. Overlay Scrollbars
  2. The Problem
  3. The Solution: scrollbar-gutter: stable;
  4. Keeping things symmetric with both-edges
  5. Caveats
  6. Browser Support
  7. In Summary

~

# Classic vs. Overlay Scrollbars

Before we jump in, there’s a distinction between two types of scrollbars that we need to make.

# Overlay Scrollbars

Overlay Scrollbars are those iOS/macOS-style scrollbars which are placed over the content. They are not shown by default, but only while the user is scrolling. To keep the content underneath visible they are semi-transparent, but that’s totally up to the user-agent (browser) to determine. While interacting with them, their size may also vary.


Figure: An Overlay Scrollbar is placed over the content.

# Classic Scrollbars

Classic Scrollbars are scrollbars that are placed in the so-called “Scrollbar Gutter”. The Scrollbar Gutter is the space between the inner border edge and the outer padding edge. With classic scrollbars, the size of the Scrollbar Gutter is the same as the width of the scrollbar. These scrollbars are usually opaque (not transparent) and take away some space from the adjacent content.


Figure: A Classic Scrollbar takes away some space from the adjacent content.

🍏 macOS User? You can switch from Overlay to Classic Scrollbars via System Preferences!

If you’re a macOS user you can switch from Overlay to Classic Scrollbars via System Preferences → General. Set “Show scroll bars” to “Always”:

Using defaults you can also enable it:

defaults write NSGlobalDomain AppleShowScrollBars -string "Always"

Some applications — such as Chrome — need to be restarted after changing the setting.

~

# The Problem

When the content of a box becomes too big (e.g. when it is overflowing), the browser will — by default — show a scrollbar. In case of a classic scrollbar this has a nasty side-effect: as the scrollbar needs some space, the available width for the content shrinks — thus the layout shifts.


Figure: As the scrollbar gets shown, the content shifts.

☝️ In case of Overlay Scrollbars there’s no layout shift, as those scrollbars get rendered over the content.

~

# The Solution: scrollbar-gutter: stable;

The scrollbar-gutter property aims to solve the problem described above.

By setting scrollbar-gutter to stable we can have the UA always show the Scrollbar Gutter, even if the box is not overflowing and no scrollbar is shown. This way we have a visually stable layout: when the box starts to overflow the scrollbar will be rendered but no layout shift will happen as space for it was already reserved.


Figure: As the scrollbar gets shown, the content does not shift as the browser had already reserved space for the scrollbar gutter.

When the scrollbar gutter is present but the scrollbar is not, the background of the scrollbar gutter is painted as an extension of the padding.

Note that this scrollbar-gutter property has no effect on the rendering of the scrollbar itself — it only affects the rendering of the gutter. The rendering of the scrollbar is controlled by the overflow property.

The default value for scrollbar-gutter is auto. With this value set, the behavior is unchanged from the one described in The Problem

~

# Keeping things symmetric with both-edges

A scrollbar-gutter value of stable can be extended with both-edges. By setting scrollbar-gutter: stable both-edges; you can achieve symmetry. As per spec:

If a scrollbar gutter would be present on one of the inline start edge or the inline end edge of the box, another scrollbar gutter must be present on the opposite edge as well.


Figure: As the scrollbar gets shown, the content does not shift. Above that the same gutter space was reserved on the opposite edge.

In a previous version of the spec both-edges was named mirror.

~

# Caveats

There are only two small caveats with this one:

  1. As for the overflow property, a scrollbar-gutter set on the root element is applied to the viewport instead.
  2. Unlike the overflow property, the browser will not propagate scrollbar-gutter from the HTML body element.

~

# Browser Support

💡 Although this post was originally published in July 2021, the section below is constantly being updated. Last update: Jan 13, 2023.

Here is an up-to-date list of browser support for CSS scrollbar-gutter:

Chromium (Blink)

✅ Available in Chromium 94 and up.

Experimental support first appeared in Chromium 88.

Firefox (Gecko)

✅ Available in Firefox 97 and up.

Safari (WebKit)

❌ No support

The pen embedded below will indicate if the browser you are currently using supports scrollbar-gutter or not:

See the Pen CSS scrollbar-gutter Support test by Bramus (@bramus) on CodePen.

To stay up-to-date regarding browser support, you can follow these tracking issues:

~

# In Summary

With the scrollbar-gutter we can prevent some unwanted layout changes caused by scrollbars. The graphic below summarizes the scenarios covered in this post:

If your browser supports scrollbar-gutter, you can also check out this CodePen demo:

See the Pen CSS scrollbar-gutter demo by Bramus (@bramus) on CodePen.

~

To help spread the contents of this post, feel free to retweet the announcement tweet:

~

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

6 Comments

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.