CORE JSC

International Technology Partnership

UI/UX

Fixing Custom Scrollbar Styles That Break Native Scrolling and Keyboard Accessibility

A custom scrollbar looks exactly right in the browser it was designed in, then shows up unstyled in another, or doubled next to the native one. Worse, a fully custom "fake scrollbar" built from a dragged div can quietly drop keyboard scrolling and mouse-wheel support that a real overflow container gets for free.

Core JSC Team·September 4, 2026
UI/UXScrollbarAccessibilityCSSCross-Browser

The Problem

A scrollable area is given a custom-styled scrollbar to match the site's design, and it looks correct in whichever browser it was built and tested in. Opened in a different browser, the same element either shows a native default scrollbar instead of the styled one, shows both a native scrollbar and a custom visual overlay at once, or — in a more serious case — a fully custom "fake scrollbar" built from a draggable element stops responding to arrow keys, Page Up/Down, or the mouse wheel entirely, even though scrolling worked fine with the mouse dragging the custom thumb.

Why It Happens

::-webkit-scrollbar is a non-standard, WebKit/Blink-only extension

The ::-webkit-scrollbar family of pseudo-elements works in Chrome, Safari, and Edge, but was never implemented by Firefox at all. Firefox instead uses the standardized scrollbar-width and scrollbar-color properties — a deliberately simpler model limited to a thin/auto/none width and a two-color track-and-thumb scheme, not the granular per-element styling WebKit's pseudo-elements allow. Relying on only one syntax leaves the other engine either falling back to its native default appearance, or — when overflow handling wasn't configured with both models in mind — rendering a native scrollbar alongside a custom visual element that was meant to replace it.

A "fake scrollbar" doesn't inherit any of the browser's built-in scrolling behavior

A custom scrollbar built as a draggable element controlling scroll position via manual scrollTop manipulation, layered over a container with overflow: hidden, gets none of what a genuinely scrollable element provides automatically. Keyboard scrolling (arrow keys, Page Up/Down, Home/End, Space), momentum/inertial scrolling, and mouse-wheel handling all come for free on a real overflow: auto or overflow: scroll element — and all of them have to be manually reimplemented, easy to forget or get subtly wrong, the moment overflow is hidden and scrolling is faked with JavaScript instead.

A custom scroll component often isn't a real, keyboard-operable control at all

A fully custom scrollbar frequently lacks a tabindex, an appropriate ARIA role, or any arrow-key event handling — invisible to anyone testing with a mouse, since visually everything still works, but it breaks the page specifically for keyboard-only and screen-reader users. This is the same underlying pattern covered for modal focus traps, showing up here in a different component.

The Fix

1. Style scrollbars with both the WebKit syntax and the standard properties together

.scroll-container {
  scrollbar-width: thin;
  scrollbar-color: #888 #eee;
}
.scroll-container::-webkit-scrollbar {
  width: 8px;
}
.scroll-container::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}
.scroll-container::-webkit-scrollbar-track {
  background: #eee;
}

Modern evergreen browsers — including current Chrome and Edge — support the standard scrollbar-width/scrollbar-color properties alongside the WebKit pseudo-elements without conflict, so both can be declared together in the same stylesheet: Firefox picks up the standard properties, WebKit-based browsers pick up the pseudo-elements, and neither falls back to an unstyled or doubled scrollbar.

2. Prefer real native overflow scrolling over a fully custom-built scrollbar

.scroll-container {
  overflow-y: auto;
  /* styled per the properties above */
}

An actual overflow: auto or overflow: scroll element gets keyboard operability, momentum scrolling, and correct accessibility semantics automatically — styling it is almost always sufficient for a custom look without needing to rebuild scrolling behavior from scratch.

3. If a custom visual scroll indicator is genuinely required, keep it as a decoration over real scrolling, not the mechanism itself

Where a design genuinely calls for a fully custom-looking scroll affordance beyond what CSS scrollbar styling can achieve, keep the actual content inside a real, keyboard-focusable overflow container, and sync a purely decorative custom element to that real scroll position — rather than making the custom element the sole thing driving scroll via manual JavaScript.

4. Test every custom scrollbar implementation with keyboard-only navigation specifically

Tab to focus the scrollable region, then verify arrow keys, Page Up/Down, Home/End, and Space all scroll correctly — the same discipline needed for verifying modal focus traps. This class of bug is invisible to anyone testing with a mouse, since the visual result and mouse-driven scrolling can look completely correct while keyboard scrolling is silently broken.

Why This Works

Each fix keeps the browser's built-in scrolling behavior intact rather than replacing it. Declaring both scrollbar styling syntaxes covers both major rendering engine families from one stylesheet instead of leaving one unstyled or doubled; preferring real overflow scrolling over a hand-built alternative means keyboard operability and momentum scrolling are inherited rather than needing to be reimplemented; keeping a custom visual element purely decorative over genuine scrolling preserves native behavior even when a fully custom look is required; and testing with the keyboard specifically catches what a mouse-only check structurally cannot.

Conclusion

A custom scrollbar that looks wrong in another browser, or that quietly breaks keyboard and mouse-wheel scrolling, is a consequence of replacing browser-native scrolling behavior rather than just styling it. Declare both the WebKit pseudo-element syntax and the standard scrollbar-width/scrollbar-color properties together, prefer real overflow-based scrolling over a fully custom-built scrollbar, keep any genuinely custom visual element as a decoration synced to real scroll position rather than the scrolling mechanism itself, and verify every implementation with keyboard-only navigation before considering it done.