Skip to content

ScrollbarWrapper: scope the dead WebKit rules to engines that use them - #1213

Draft
JeanMarcMilletScality wants to merge 1 commit into
development/1.0from
bugfix/CUI-scrollbar-global-style
Draft

JeanMarcMilletScality wants to merge 1 commit into
development/1.0from
bugfix/CUI-scrollbar-global-style

Conversation

@JeanMarcMilletScality

Copy link
Copy Markdown
Contributor

TL;DR — ScrollbarWrapper: the forty lines of WebKit scrollbar styling have had no effect in any current browser, and the 8px they name is not the bar anyone sees; they are now scoped to the engines that would actually use them, with no change to what renders today.

Context / Why

The component styles scrollbars two ways at once: the two standard properties (scrollbar-color, scrollbar-width) and a block of ::-webkit-scrollbar pseudo-element rules. Only the first pair is doing anything. This came up because a hard-coded 8px read off this file was about to be published as a constant for other components to compensate against — and the real bar is 11px.

🧩 Approach

Two independent reasons the WebKit block cannot apply, one of them measured:

Probe, on a running page with this component mounted Bar width
A scroller inheriting the global scrollbar-width: thin 11px
The same probe forced to scrollbar-width: auto 15px
What ::-webkit-scrollbar { width: 8px } would give never observed

Chromium ignores an element's ::-webkit-scrollbar rules once that element has author-specified standard scrollbar properties — and this component sets scrollbar-width on *, so every element qualifies, always. The second reading is what makes this conclusive rather than inferred: under scrollbar-width: auto the WebKit width: 8px would still win if the pseudo-elements were being consulted at all, and it measured the platform default instead.

Separately, the rules were authored nested inside the universal selector:

// before — compiles to `* ::-webkit-scrollbar`, a descendant selector
* {
  ::-webkit-scrollbar { width: 8px; }      // ←
  scrollbar-width: thin;
}

// after — flat, so it can also reach the root scroller
@supports not (scrollbar-width: thin) {    // ←
  *::-webkit-scrollbar { width: 8px; }     // ←
}
* { scrollbar-width: thin; }

html has no ancestor element, so the old form could never have matched the page's own scrollbar in any engine, WebKit included.

So the block goes behind @supports not (scrollbar-width: thin), which is what it has effectively been all along: a fallback for engines without the standard properties. Nothing changes for any engine that has them, which is every current one. The guideline gains a line saying the bar's width belongs to the engine — it is a keyword, not a length, and differs per engine, per platform and under a consumer override — so room for it is reserved with scrollbar-gutter: stable rather than a pixel value.

🔍 Review focus

  • 🟡 Moderate — scrollbarwrapper/ScrollbarWrapper.component.tsx — the behaviour change, if any, is confined to a browser that supports ::-webkit-scrollbar but not scrollbar-width (Safari below 18.2, Chromium below 121). There the rules now apply where they previously matched only non-root elements, so such a browser gets more of the intended styling, not less. Worth a second opinion on whether that window matters.
  • ⚪ Minor — same file — the thumb, track, hover, button and corner rules move with the width rule; none of them was reachable either.

🧪 How to test

  1. Open any Storybook story with a scrollable area in Chrome. The scrollbar should look exactly as it does on development/1.0 — thin and themed, not the platform default.
  2. Repeat in Firefox: unchanged there too, since Firefox never supported the WebKit pseudo-elements.
  3. In devtools, measure a scroller's offsetWidth - clientWidth. It should read the same before and after this change (11px on a standard Chromium setup, not 8px).
  4. To exercise the fallback branch, disable scrollbar-width support — easiest in a browser that lacks it rather than by simulation.

Follow-up

  • The same component is implicated in a separate, unrelated defect: its rules are cleared document-wide after a navigation when more than one copy of the library renders it. That has its own diagnosis and is not touched here.

🔗 References


🤖 Generated with Claude Code

…gines that use them

Setting scrollbar-width or scrollbar-color on an element makes Chromium
ignore that element's ::-webkit-scrollbar rules, and this component sets
both on every element. The forty lines of WebKit pseudo-element styling
below them have therefore had no effect for some time: measured on a
running page, a scroller renders the engine's own thin bar at 11px and
never the 8px those rules name.

Two things kept that invisible. The rules were nested inside the
universal selector, which compiles to a descendant combinator, so they
could never have reached the root scroller in any engine. And the width
they name reads like a fact about the library, which is where a
consumer's temptation to compensate for a fixed number comes from.

Put them behind @supports not (scrollbar-width: thin), where they are
what they actually are -- a fallback for engines without the standard
properties -- and write the selectors flat so that fallback also covers
the root. No change on any engine that supports the standard properties,
which is every current one. The guideline gains a line saying the bar's
width belongs to the engine and to reserve room with scrollbar-gutter
rather than a pixel value.
@bert-e

bert-e commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Hello jeanmarcmilletscality,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval ⭐
/bypass_build_status Bypass the build and test status ⭐
/bypass_commit_size Bypass the check on the size of the changeset TBA ⭐
/bypass_incompatible_branch Bypass the check on the source branch prefix ⭐
/bypass_jira_check Bypass the Jira issue check ⭐
/bypass_peer_approval Bypass the pull request peers' approval ⭐
/bypass_leader_approval Bypass the pull request leaders' approval ⭐
/bypass_source_branch_lineage Bypass the cross-branch contamination check ⭐
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e

bert-e commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • one peer

Peer approvals must include at least 1 approval from the following list:

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants