fix(web): restore always-visible, grabbable scrollbars #511

Merged
Claude-Run merged 1 commit from fix/BUNYIP-509-visible-scrollbars into main 2026-08-11 03:08:54 +02:00
Member

bunyip-web/input.css ended with a global ::-webkit-scrollbar { display: none } + * { scrollbar-width: none } pair that removed the scrollbar from every scroll container in the app, on every engine. There was no indicator that a pane scrolled, no indicator of position or remaining content, and nothing to grab and drag: scrolling was reduced to wheel or touchpad. The horizontal cases were the worst of it, since an overflow-x-auto table or code block gave no sign at all that content continued past the right edge. That is an accessibility defect, not a styling preference.

Both rules are replaced with explicit, always-visible styling at the same place in the file: scrollbar-width: auto (never thin) plus a scrollbar-color for Firefox and the standards engines, and a 14px ::-webkit-scrollbar with a painted track, a full-width rounded thumb and a distinct :hover state for Chromium and Safari. Declaring the width is also what opts those engines out of the fading OS overlay bar. Every colour comes from the existing theme tokens (--muted, --muted-foreground, --foreground), so light, dark and both high-contrast variants track automatically; the thumb measures 5.3:1 against the light background and 12.5:1 against the dark one. scrollbar-gutter: stable on html and on the vertical scroll containers keeps content from shifting when a pane gains or loses its bar. No auto-hide, fade, overlay or hover-to-reveal behaviour is introduced anywhere.

The committed Tailwind output bunyip-web/assets/styles.css is rebuilt with the pinned tailwindcss 4.3.0 from bun.lock; the only change in it is the replaced scrollbar block.

scripts/check-scrollbars.nu is the new guard, wired into check.yml and just check alongside the other gates. It fails the build if scrollbar-width: none, scrollbar-width: thin or a display: none on any ::-webkit-scrollbar* pseudo-element reappears in the authored or the built CSS, and also if the visible styling goes missing from either file, so a rebuild that dropped it or a stale asset fails here instead of shipping. CSS comments are stripped before matching, so the comment naming the removed rules does not read as a violation. --self-test exercises eleven cases (authored and minified compliant forms, each hiding shape, a stripped stylesheet, a commented mention in both directions, a missing file).

Completeness sweep, every scroll container in bunyip-web:

Site Container Class
src/views/layout.rs:538 sidebar nav, overflow-y-auto compliant: visible bar + stable gutter
src/views/layout.rs:660 APP_MAIN_CLASS main pane, overflow-y-auto compliant: visible bar + stable gutter
src/handlers/dashboard.rs:635 modal body, max-h-[80vh] overflow-y-auto compliant: visible bar + stable gutter
src/handlers/admin/users.rs:605 admin users table wrapper, overflow-x-auto compliant: 14px horizontal bar (gutter N/A, the bar sits on the block edge)
src/handlers/dashboard.rs:701 inline code block, overflow-x-auto compliant: 14px horizontal bar
src/handlers/dashboard.rs:718 pre block, overflow-x-auto compliant: 14px horizontal bar
src/skin/content.rs:706 .docs-article pre, overflow-x: auto compliant: styled by the same global rules
src/skin/content.rs:708 .docs-article table, overflow-x: auto compliant: styled by the same global rules
document scroller (html) public pages and any short viewport compliant: visible bar + stable gutter
16 overflow-hidden markup sites shells, cards, dropdowns, avatars, hero sections N/A: hidden clips, it never scrolls, so there is no bar to show
src/views/avatar_picker.rs:39,40, src/handlers/admin/users.rs:667 inline overflow: hidden (sr-only input, avatar circle, shimmer) N/A: same reason
src/views/layout.rs:800,807,816,822 test assertions on those class strings N/A: test code, not markup

#BUNYIP-509

`bunyip-web/input.css` ended with a global `::-webkit-scrollbar { display: none }` + `* { scrollbar-width: none }` pair that removed the scrollbar from every scroll container in the app, on every engine. There was no indicator that a pane scrolled, no indicator of position or remaining content, and nothing to grab and drag: scrolling was reduced to wheel or touchpad. The horizontal cases were the worst of it, since an `overflow-x-auto` table or code block gave no sign at all that content continued past the right edge. That is an accessibility defect, not a styling preference. Both rules are replaced with explicit, always-visible styling at the same place in the file: `scrollbar-width: auto` (never `thin`) plus a `scrollbar-color` for Firefox and the standards engines, and a 14px `::-webkit-scrollbar` with a painted track, a full-width rounded thumb and a distinct `:hover` state for Chromium and Safari. Declaring the width is also what opts those engines out of the fading OS overlay bar. Every colour comes from the existing theme tokens (`--muted`, `--muted-foreground`, `--foreground`), so light, dark and both high-contrast variants track automatically; the thumb measures 5.3:1 against the light background and 12.5:1 against the dark one. `scrollbar-gutter: stable` on `html` and on the vertical scroll containers keeps content from shifting when a pane gains or loses its bar. No auto-hide, fade, overlay or hover-to-reveal behaviour is introduced anywhere. The committed Tailwind output `bunyip-web/assets/styles.css` is rebuilt with the pinned tailwindcss 4.3.0 from `bun.lock`; the only change in it is the replaced scrollbar block. `scripts/check-scrollbars.nu` is the new guard, wired into `check.yml` and `just check` alongside the other gates. It fails the build if `scrollbar-width: none`, `scrollbar-width: thin` or a `display: none` on any `::-webkit-scrollbar*` pseudo-element reappears in the authored or the built CSS, and also if the visible styling goes missing from either file, so a rebuild that dropped it or a stale asset fails here instead of shipping. CSS comments are stripped before matching, so the comment naming the removed rules does not read as a violation. `--self-test` exercises eleven cases (authored and minified compliant forms, each hiding shape, a stripped stylesheet, a commented mention in both directions, a missing file). Completeness sweep, every scroll container in `bunyip-web`: | Site | Container | Class | | --- | --- | --- | | `src/views/layout.rs:538` | sidebar nav, `overflow-y-auto` | compliant: visible bar + stable gutter | | `src/views/layout.rs:660` | `APP_MAIN_CLASS` main pane, `overflow-y-auto` | compliant: visible bar + stable gutter | | `src/handlers/dashboard.rs:635` | modal body, `max-h-[80vh] overflow-y-auto` | compliant: visible bar + stable gutter | | `src/handlers/admin/users.rs:605` | admin users table wrapper, `overflow-x-auto` | compliant: 14px horizontal bar (gutter N/A, the bar sits on the block edge) | | `src/handlers/dashboard.rs:701` | inline `code` block, `overflow-x-auto` | compliant: 14px horizontal bar | | `src/handlers/dashboard.rs:718` | `pre` block, `overflow-x-auto` | compliant: 14px horizontal bar | | `src/skin/content.rs:706` | `.docs-article pre`, `overflow-x: auto` | compliant: styled by the same global rules | | `src/skin/content.rs:708` | `.docs-article table`, `overflow-x: auto` | compliant: styled by the same global rules | | document scroller (`html`) | public pages and any short viewport | compliant: visible bar + stable gutter | | 16 `overflow-hidden` markup sites | shells, cards, dropdowns, avatars, hero sections | N/A: `hidden` clips, it never scrolls, so there is no bar to show | | `src/views/avatar_picker.rs:39,40`, `src/handlers/admin/users.rs:667` | inline `overflow: hidden` (sr-only input, avatar circle, shimmer) | N/A: same reason | | `src/views/layout.rs:800,807,816,822` | test assertions on those class strings | N/A: test code, not markup | #BUNYIP-509
fix(web): restore always-visible, grabbable scrollbars
All checks were successful
E2E / PR gate (pull_request) Successful in 44s
Check / fmt + clippy + build + tests (pull_request) Successful in 8m36s
Create release / Create release from merged PR (pull_request) Has been skipped
e0c79897c6
`bunyip-web/input.css` ended with a global `::-webkit-scrollbar { display: none }` + `* { scrollbar-width: none }` pair that removed the scrollbar from every scroll container in the app, on every engine. There was no indicator that a pane scrolled, no indicator of position or remaining content, and nothing to grab and drag: scrolling was reduced to wheel or touchpad. The horizontal cases were the worst of it, since an `overflow-x-auto` table or code block gave no sign at all that content continued past the right edge. That is an accessibility defect, not a styling preference.

Both rules are replaced with explicit, always-visible styling at the same place in the file: `scrollbar-width: auto` (never `thin`) plus a `scrollbar-color` for Firefox and the standards engines, and a 14px `::-webkit-scrollbar` with a painted track, a full-width rounded thumb and a distinct `:hover` state for Chromium and Safari. Declaring the width is also what opts those engines out of the fading OS overlay bar. Every colour comes from the existing theme tokens (`--muted`, `--muted-foreground`, `--foreground`), so light, dark and both high-contrast variants track automatically; the thumb measures 5.3:1 against the light background and 12.5:1 against the dark one. `scrollbar-gutter: stable` on `html` and on the vertical scroll containers keeps content from shifting when a pane gains or loses its bar. No auto-hide, fade, overlay or hover-to-reveal behaviour is introduced anywhere.

The committed Tailwind output `bunyip-web/assets/styles.css` is rebuilt with the pinned tailwindcss 4.3.0 from `bun.lock`; the only change in it is the replaced scrollbar block.

`scripts/check-scrollbars.nu` is the new guard, wired into `check.yml` and `just check` alongside the other gates. It fails the build if `scrollbar-width: none`, `scrollbar-width: thin` or a `display: none` on any `::-webkit-scrollbar*` pseudo-element reappears in the authored or the built CSS, and also if the visible styling goes missing from either file, so a rebuild that dropped it or a stale asset fails here instead of shipping. CSS comments are stripped before matching, so the comment naming the removed rules does not read as a violation. `--self-test` exercises eleven cases (authored and minified compliant forms, each hiding shape, a stripped stylesheet, a commented mention in both directions, a missing file).

Completeness sweep, every scroll container in `bunyip-web`:

| Site | Container | Class |
| --- | --- | --- |
| `src/views/layout.rs:538` | sidebar nav, `overflow-y-auto` | compliant: visible bar + stable gutter |
| `src/views/layout.rs:660` | `APP_MAIN_CLASS` main pane, `overflow-y-auto` | compliant: visible bar + stable gutter |
| `src/handlers/dashboard.rs:635` | modal body, `max-h-[80vh] overflow-y-auto` | compliant: visible bar + stable gutter |
| `src/handlers/admin/users.rs:605` | admin users table wrapper, `overflow-x-auto` | compliant: 14px horizontal bar (gutter N/A, the bar sits on the block edge) |
| `src/handlers/dashboard.rs:701` | inline `code` block, `overflow-x-auto` | compliant: 14px horizontal bar |
| `src/handlers/dashboard.rs:718` | `pre` block, `overflow-x-auto` | compliant: 14px horizontal bar |
| `src/skin/content.rs:706` | `.docs-article pre`, `overflow-x: auto` | compliant: styled by the same global rules |
| `src/skin/content.rs:708` | `.docs-article table`, `overflow-x: auto` | compliant: styled by the same global rules |
| document scroller (`html`) | public pages and any short viewport | compliant: visible bar + stable gutter |
| 16 `overflow-hidden` markup sites | shells, cards, dropdowns, avatars, hero sections | N/A: `hidden` clips, it never scrolls, so there is no bar to show |
| `src/views/avatar_picker.rs:39,40`, `src/handlers/admin/users.rs:667` | inline `overflow: hidden` (sr-only input, avatar circle, shimmer) | N/A: same reason |
| `src/views/layout.rs:800,807,816,822` | test assertions on those class strings | N/A: test code, not markup |

#BUNYIP-509
Claude-Run deleted branch fix/BUNYIP-509-visible-scrollbars 2026-08-11 03:08:54 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!511
No description provided.