DEV Community

Cover image for Easy Overlay Scrollbars with Reactive Design
jonosellier
jonosellier

Posted on • Updated on

Easy Overlay Scrollbars with Reactive Design

As of Chromium 114 (June 2023) overlay scrollbar functionality has been removed and therefore this guide is no longer valid. While I understand wanting to conform to a standard, it is unfortunate that this functionality has been removed. Being unable to have a native scrollbar overlay content at the developer's discretion negatively affects the number of ways one can lay content out without UI items jumping around due to scrollbar space requirements changing.

Why even use overlay scrollbars?

Overlay scrollbars are great because they don't affect the width of the content as they appear and disappear. When I discovered this trick, I was specifically looking to solve the problem of content reflow as a page went from <100vh to >100vh. The other nice thing with overlay scrollbars is that they can more seamlessly get out of the way when you aren't using them.

Great, how do I do it?

With overflow: overlay. Seems too easy right? Well it's Chromium only (so Edge, Brave, Chrome) so it can't be your only overflow option. Ideally, you want to wrap it in @supports(overflow: overlay) with a fallback to auto or scroll. This is what it looks like on Windows without any further styling:

What overly scrollbars look like on Windows without any further styling

You'll notice that the scrollbars literally just go over the content. We'll need to make the scrollbars look a bit better:

  • Transparent background so we can see the content it overlays
  • Semitransparent scrollbar for the same reason
  • Small enough it doesn't get in the way
  • Big enough for a mouse to click and grab (because our grandfathers deserve to scroll how they're used to)

So all we have to do is use some scrollbar CSS (which is supported on Chromium too) to make it look a bit better...

Apply the following CSS...

body {
  overflow: overlay;
}

*::-webkit-scrollbar {
  display: block;
  width: 16px;
}

*::-webkit-scrollbar-button {
  display: none;
}

*::-webkit-scrollbar-track {
  background-color: #00000000;
}

*::-webkit-scrollbar-track-piece {
  background-color: #00000000;
}

*::-webkit-scrollbar-thumb {
  background-color: #00000040;
  border: 1px solid #ffffff40;
  border-radius: 24px;
}
Enter fullscreen mode Exit fullscreen mode

...and we get this:

The scrollbar in a usable but imperfect form

You'll see that the scrollbar is wide enough to grab with a mouse (it's as wide as it is on Windows, 16px) but a bit too wide as a pure indicator. Those last 2 points are important but seem to be a bit contradictory. We could make the scrollbar get bigger on hover but you need to hit that small target before it gets bigger so you might as well keep it small. Unless we...

(Ab)use shadows to make things more usable

If we set the shadow behind the scrollbar to be some solid inset shadow and a large, transparent border, then we can make the bar itself transparent, so the only thing we see is the inset shadow, that is smaller than the bar itself due to the border.

*::-webkit-scrollbar-thumb {
  background-color: #00000000;
  border: 5px solid transparent;
  border-radius: 24px;
  box-shadow: 4px 0px 0px 4px #00000040 inset;
}

*::-webkit-scrollbar-thumb:hover {
  background-color: #00000040;
  border: 0px solid transparent;
  box-shadow: none;
}
Enter fullscreen mode Exit fullscreen mode

The result we get is a bar that looks 6px wide but is really 16px:
A small scrollbar

And when we hover near the "smaller bar" (within 5px), it looks just the same as before with the same pointer target size since the element itself is not any smaller.

Now if we extract that color to a CSS variable we can go further!

Going even further

We gotta extract that scrollbar color to a variable, let's call it --scrollbar-color.

Then let's add a few more CSS rules to change this scrollbar color based on whether or not the page/element is focused. This is the new CSS that uses variables and :hover, etc. selectors:

* {
  --scrollbar-color: #00000000;
}

*:hover, *:focus, *:focus-within {
  --scrollbar-color: #00000040 !important;
}

*::-webkit-scrollbar-thumb {
  background-color: #00000000;
  border: 5px solid transparent;
  border-radius: 24px;
  box-shadow: 4px 0px 0px 4px var(--scrollbar-color) inset;
}

*::-webkit-scrollbar-thumb:hover {
  background-color: var(--scrollbar-color);
  border: 0px solid transparent;
  box-shadow: none;
}
Enter fullscreen mode Exit fullscreen mode

This will make your scrollbar invisible unless you hover over the element (or page).

But what if we want it to look like a mobile phone's indicator that disappears unless we are currently scrolling? Well for that we finally need JavaScript

Finally needing JavaScript

We got pretty far with CSS but it's time to listen for events, scroll events. Below we add a class to body whenever we are currently scrolling.

var barTimeout;

document.body.onscroll = () => {
  if(barTimeout){
    clearTimeout(barTimeout); //clear to reset
  }
  barTimeout = setTimeout(() => {
    document.body.classList.remove('scrolling');
  }, 500); //0.5s delay
  document.body.classList.add('scrolling');
};
Enter fullscreen mode Exit fullscreen mode

Then we adjust our CSS a little to instead change the --scrollbar-color on body.scrolling:

body {
  --scrollbar-color: #00000000;
}

body.scrolling {
  --scrollbar-color: #00000040 !important;
}
Enter fullscreen mode Exit fullscreen mode

Final touches for production

Just make sure to wrap all this CSS in @supports(overflow: overlay) and so on! It will work in this current state on 79% of browsers we want to target* but we need to support Safari and Firefox still!

* Since we are emulating mobile device scrollbars, we can only look at desktop browsers

The final product

Available on JSFiddle with hover effect here and scroll effect here


Let me know if this helps you out in any way! 🚀

Top comments (5)

Collapse
 
kumikumi profile image
Mikko Ankkala

This needs to be updated. It's the top result on Google for "CSS overlay scrollbar", but "overflow: overlay" has been deprecated and I could not find a working alternative.

Collapse
 
jonosellier profile image
jonosellier

Hi, just wanted to reach out and let you know this feature has finally been soft-deprecated 18 months after I posted this. If you were using this, be aware it is no longer functional as of Chromium 114.

Collapse
 
jonosellier profile image
jonosellier

While yes it is deprecated as far as W3 is concerned, Chromium has not indicated that they will be depreciating it.

So, yes, this is nonstandard but it is supported on 80% of desktop systems [src] (and all mobile devices and Safari use overlay scrollbars anyways) so it's still worthwhile to use in my opinion. Once you wrap it in a @supports block and have a good experience for users who cannot use this property, you will be fine.

As a final note: Seeing as more and more browsers have overlay scrollbars by default, it might not be necessary to even use this trick. Unless you are planning on overlaying your scrollbar on top of dynamic content (like a minimap in VSCode, or a timeline slider in a video editor), the default overlay scrollbars from the browser is probably enough.

Collapse
 
plutonium239 profile image
Samarth Bhatia • Edited

How do browsers "have" overlay scrollbars?
Are they injecting CSS of their own? I really dont understand how to use it, especially with the scrollbar-gutter functionality (the caniuse page for overflow:overlay says that it is deprecating in favor of scrollbar-gutter)

Thread Thread
 
jonosellier profile image
jonosellier

It would depend on the implementation of UI for each browser but most modern browsers have a base-level stylesheet called a user-agent stylesheet which defines styles for all elements on a web page. From font size to scrollbars, everything has a base style.