Scroll to the Future

This is an interesting read on the current state of scrollbars and how to control their behavior across operating systems and browsers. The post also highlights a bunch of stuff I didn’t know about, like Element.scrollIntoView() and the scroll-behavior CSS property.

My favorite part of all though? It has to be this bit:

In the modern web, relying heavily on custom JavaScript to achieve identical behavior for all clients is no longer justified: the whole idea of “cross-browser compatibility” is becoming a thing of the past with more CSS properties and DOM API methods making their way into standard browser implementations.

In our opinion, Progressive Enhancement is the best approach to follow when implementing non-trivial scrolling in your web projects.

Make sure you can provide the best possible minimal, but universally supported UX, and then improve with modern browser features in mind.

Speaking of the cross-browser behavior of scrollbars, Louis Hoebregts also has a new post that notes how browsers do not include the scrollbar when dealing with vw units and he provides a nice way of handling it with CSS custom properties.

Designing for “Show scroll bars”

In macOS, users have the ability to set when they want to see scrollbars in windows. This affects all windows in the operating system, including in web browsers. They have three choices:

  • Automatically based on mouse or trackpad
  • When scrolling
  • Always

Which means you are either in a state where you see them all the time, or a state where you only see them once scrolling has been started through some other means.


Custom Scrollbars Mixin

Scrollbars are one of those UI components that are present on almost every page of the internet, yet we (developers) have little to no control over it. Some browsers give us the ability to customize their appearance but for most browsers including Firefox it just is not possible.

Still, Chrome and Internet Explorer (yes) make it possible for us to define custom styles for scrollbars. However the syntax horribly complex, and of course, definitely not standard. Welcome to the proprietary world. This is why you might want to have a little mixin to easily customize your scrollbars. Right?


More Elegant Fix for Jumping Scrollbar Issue

If you move from one page of a site without a scrollbar to another with a scrollbar, you'll see a slight layout shift as things squeeze inward a bit to make room for the scrollbar.

A classic fix was html { overflow-y: scroll; } to force the scrollbar all the time. Ayke van Laëthem has found a more elegant solution in html { margin-left: calc(100vw - 100%); } which works because vw accounts for the scrollbar and % doesn't, and... just read it as there are a few more things you'll need to be aware of anyway.

Pretty sweet for a first blog post Ayke!


The scrollbar set of CSS properties is a proprietary style hook from Internet Explorer 5.5, which let designers create custom themes for the browser's native scrollbars. Currently, it is exposed behind the -webkit vendor prefix for use in browsers using the Webkit (and Blink) rendering engine. This almanac entry is an overview, for a more complete breakdown of working with custom scrollbars, please read this CSS-Tricks article.

body::-webkit-scrollbar {
    width: 1em;
body::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
body::-webkit-scrollbar-thumb {
  background-color: darkgrey;
  outline: 1px solid slategrey;

The -webkit-scrollbar family of properties consists of seven different pseudo-elements that, together, comprise a full scrollbar UI element:

  1. ::-webkit-scrollbar addresses the background of the bar itself. It is usually covered by the other elements
  2. ::-webkit-scrollbar-button addresses the directional buttons on the scrollbar
  3. ::-webkit-scrollbar-track addresses the empty space “below” the progress bar
  4. ::-webkit-scrollbar-track-piece is the top-most layer of the the progress bar not covered by the draggable scrolling element (thumb)
  5. ::-webkit-scrollbar-thumb addresses the draggable scrolling element that resizes depending on the size of the scrollable element
  6. ::-webkit-scrollbar-corner addresses the (usually) bottom corner of the scrollable element, where two scrollbars might meet
  7. ::-webkit-resizer addresses the draggable resizing handle that appears above the scrollbar-corner at the bottom corner of some elements

In addition to these pseudo-elements, there are also eleven pseudo-selector classes that aren't required, but provide designers with the power to style various states and interactions of the scrollbar UI. A full breakdown of those pseudo-selectors, and a detailed example, can be found in this CSS-Tricks article.

Check out this Pen!

Points of Interest

  • If there is no qualifying selector preceding the various pseudo-elements, the styles will apply to any scrollbar that may appear on the page.
  • Setting -webkit-scrollbar styles is a good way to force your webpage to show horizontal or vertical scrollbars on versions of Mac OS newer than Lion, on which scrollbars are usually hidden by default.
  • Since this property is behind a -webkit vendor prefix, several jQuery plugins have been written to “polyfill” or extend this functionality to other browsers. One such plugin is jScrollPane.

Other Resources

Browser Support

Chrome Safari Firefox Opera IE Android iOS
yep yep nope 15+ nope yep yep

Force Vertical Scrollbar

html {
  overflow-y: scroll;

This is invalid CSS, but it works in everything except Opera. The reason for this is to prevent "centering jumps" when navigating back and forth between pages with enough content to have a vertical scroll bar and pages that do not.

Eliminate “Jumps” in Horizontal Centering By Forcing a Scroll Bar

You are likely aware of the page centering technique of adding auto left and right margins to an outer div:

#page-wrap {
  margin: 0 auto;

One of the shortcomings of this technique is that when used on websites with multiple pages, the layout can appear to "jump" a little bit when going back and forth between pages that require scroll bars and pages that do not. This is because the ~16px width of the scroll bar in the browser window causes the content area to become that much narrower and the wrap div re-centers itself in the narrower content area causing the jump.

One way to eliminate this jump is to force scroll bars onto every page regardless if they need them or not. This may annoy some purists out there, but I think it's a decent solution.

This is one way to do it, which forces the page to always be just a little bit taller than the browser window forcing a right scroll bar:

html {
  height: 100%;
  margin-bottom: 0.01em;

It's a good idea, but it doesn't seem to get the job done in Firefox.

Here is a way you can force only the right sidebar with a nasty and unsemantic hack:

#scroll {
    position: absolute;
    top: 0;
    bottom: -0.1px;
    width: 1em;
    z-index: -1;

Then just include an empty div in your HTML with an id of "scroll". Like I said, this is kind of a nasty way to do it, here is a much cleaner way:

html {
  height: 102%;

Here is another solution, which effectively forces both horizontal and vertical scrollbars:

html {
  overflow: scroll;

You can see an example of this working in this example. It would be nice if we could get just the vertical scroll bar by assigning overflow-y to scroll, but again it doesn't work in Firefox. UPDATE: Actually, I've been shown the light. Assigning overflow-y to scroll does work, and it works in Firefox, Safari, and IE 6, and that makes it the best solution:

html {
  overflow-y: scroll;