Skip to content

Overlay scrollbars: painting, hover/active styling, and thumb dragging#461

Open
UMCEKO wants to merge 1 commit into
DioxusLabs:mainfrom
UMCEKO:pr/scrollbars
Open

Overlay scrollbars: painting, hover/active styling, and thumb dragging#461
UMCEKO wants to merge 1 commit into
DioxusLabs:mainfrom
UMCEKO:pr/scrollbars

Conversation

@UMCEKO

@UMCEKO UMCEKO commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Stacked on #460 (contains its commit — the test infrastructure dev-dependencies; will rebase once it lands).

blitz previously never painted scrollbars: an overflow: auto/scroll container gave no visual indication that it scrolls or where within the content the viewport sits. This implements overlay scrollbars end-to-end, in two commits:

Painting. An overlay thumb (no reserved gutter, so no layout change) per overflowing axis: always for overflow: scroll, only when the content overflows for overflow: auto, never for hidden/clip (programmatic-only scrolling). Geometry derives from Layout::scroll_width/scroll_height and node.scroll_offset; the thumb is drawn unscrolled, above the clipped content, inside the opacity/filter layer. Like other overlay scrollbar UIs (macOS, Firefox on Linux), thumbs only appear while the scroll container is hovered or scrolled away from the origin — beyond matching platform conventions, this keeps thumbs out of static reftest screenshots: an always-visible variant regressed 10 WPT overflow reftests (whose reference pages cannot scroll); the hover/scroll rule regresses none.

Interaction. Thumb geometry lives in a shared helper on Node (scrollbar_thumb / wants_scrollbar / scrollbar_drag_ratio) so painting and hit testing cannot drift. Pointer handling gains a DragMode::ScrollbarDrag state: on pointerdown the layout ancestor chain of the hit node is walked for a scroll container whose thumb contains the pointer (the hit test returns the content under the overlay thumb). While dragging, pointer movement maps thumb px to content px via the track ratio and scrolls through the existing clamped scroll_by path; scrollbar drags are not dispatched to the page, and the existing DragMode handling suppresses the synthetic click on release. The document tracks which thumb the pointer is over (hovered_scrollbar, repainting on change) and the painter renders three thumb states: normal, hovered, dragged — a dragged thumb stays visible if the pointer leaves the container mid-drag.

Tests: pixel-level paint tests in packages/blitz-html/tests/scrollbars.rs (render via anyrender_vello_cpu, assert pixels) and synthetic-pointer-event tests in packages/blitz-html/tests/scrollbar_drag.rs driving the EventDriver (drags scroll proportionally and clamp; content drags don't scroll; hover/drag restyle the thumb).

Not yet implemented (follow-ups): css-scrollbars-1 styling (scrollbar-color/scrollbar-width — implemented and tested locally, but blocked on enabling those two properties for the servo engine in stylo, where their engine = "gecko" gate in longhands.toml appears to be the only obstacle; will PR stylo), track click-to-page, show/hide fade animations.

@UMCEKO UMCEKO changed the title Paint overlay scrollbars for scroll containers Overlay scrollbars: painting, hover/active styling, and thumb dragging Jun 13, 2026
@Phirios

This comment was marked as resolved.

@Phirios

This comment was marked as resolved.

blitz previously never painted scrollbars: an overflow: auto/scroll
container gave no visual indication that it scrolls or where within the
content the viewport sits.

Draw an overlay thumb (no reserved gutter, so no layout change) per
overflowing axis: always for overflow: scroll, only when the content
overflows for overflow: auto, never for hidden/clip (programmatic-only
scrolling). Geometry derives from Layout::scroll_width/scroll_height and
node.scroll_offset; the thumb is drawn unscrolled, above the clipped
content, inside the opacity/filter layer.

Like other overlay scrollbar UIs (macOS, Firefox on Linux), thumbs only
appear while the scroll container is hovered or scrolled away from the
origin. Beyond matching platform conventions this keeps thumbs out of
static reftest screenshots: an always-visible variant regressed 10 WPT
overflow reftests whose reference pages cannot scroll; the hover/scroll
rule regresses none.

Pixel-level tests in packages/blitz-html/tests/scrollbars.rs.

Not yet implemented: thumb hit-testing/dragging, css-scrollbars-1
styling (scrollbar-width/scrollbar-color), and show/hide fade
animations.
@UMCEKO UMCEKO marked this pull request as ready for review June 15, 2026 23:20
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