Skip to content

fix(web): stabilize chat scrolling and mobile alignment - #1278

Merged
tiann merged 2 commits into
tiann:mainfrom
techotaku39:fix/web-chat-scroll-containment
Aug 1, 2026
Merged

fix(web): stabilize chat scrolling and mobile alignment#1278
tiann merged 2 commits into
tiann:mainfrom
techotaku39:fix/web-chat-scroll-containment

Conversation

@techotaku39

@techotaku39 techotaku39 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • keep document-level overflow from creating a second scrollbar and stale blank space around long chat sessions
  • scope document/root containment to chat views while preserving normal document scrolling on login and other non-chat routes
  • reserve symmetric chat scrollbar gutters only on touch-first devices, then compensate for the measured physical gutter so the original mobile inset remains unchanged
  • leave pointer/hover desktop chat spacing and scrollbar layout unchanged

Problem

Some chat sessions could intermittently gain two vertical scrollbars, especially after an image attachment changed size during rendering. The outer document scrollbar could retain a stale scroll range and expose a large blank area below the app until the page was refreshed.

On mobile, the remaining chat scrollbar also consumed width on the right side of the scroll viewport. Centered chat content was therefore shifted left and had visibly asymmetric side spacing.

Changes

  • scope html, body, and #root overflow containment to pages containing the chat viewport so temporary chat child measurements cannot expand the document scroll range
  • add chat-specific viewport/content classes instead of changing every .app-scroll-y surface
  • under (hover: none) and (pointer: coarse):
    • use scrollbar-gutter: stable both-edges
    • measure the actual reserved gutter and subtract it from the chat content padding
    • retain the original padding on browsers/devices that use overlay scrollbars and reserve no physical gutter
  • retain the original p-3 content spacing on desktop pointer devices

Testing

  • bun typecheck
  • bun run test:web — 193 files, 1705 tests passed
  • production build and manual testing through the embedded Hub web app on Windows/Chromium at desktop and mobile viewport sizes
  • verified image-attachment sessions no longer create a second document scrollbar or blank page tail
  • verified touch-first layouts retain the original left inset and use the same effective inset on the right

AI disclosure

Code and PR text were prepared with OpenAI GPT-5.6-Sol and manually tested/reviewed.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Global document locking can make login/binding controls unreachable on short viewports — html, body, and #root now hide overflow, but LoginPrompt is a full-height centered layout without an inner scroll owner. In landscape or after the mobile keyboard shrinks the viewport, overflow is clipped instead of scrollable. Evidence: web/src/index.css:296, web/src/index.css:308, web/src/components/LoginPrompt.tsx:116.
    Suggested fix:

    html,
    body {
        overflow-x: hidden;
        overflow-y: auto;
    }
    
    #root {
        overflow: visible;
    }
    
    html:has(.chat-scroll-y),
    body:has(.chat-scroll-y),
    html:has(.chat-scroll-y) #root {
        overflow: hidden;
    }
  • [Minor] Touch devices with overlay scrollbars lose almost all chat side padding — scrollbar-gutter reserves layout space only for classic scrollbars, while the content padding is reduced from 0.75rem to 0.125rem for every coarse pointer. Common mobile overlay-scrollbar layouts therefore render messages about 2px from both edges. Evidence: web/src/index.css:321, web/src/index.css:325, web/src/components/AssistantChat/HappyThread.tsx:1420.
    Suggested fix:

    @media (hover: none) and (pointer: coarse) {
        .chat-scroll-y {
            scrollbar-gutter: stable both-edges;
        }
    
        /* Keep the existing p-3 fallback when no physical gutter is reserved. */
    }

Summary

Review mode: initial

Two issues found: document-level overflow containment is not safe for the non-scrollable authentication shell, and the gutter compensation does not preserve padding on overlay-scrollbar mobile browsers.

Testing

Not run (review automation; PR code was not executed). Add browser coverage for a short/landscape login viewport and a touch viewport using overlay scrollbars.

HAPI Bot

Comment thread web/src/index.css
* example while an attachment image is being measured) cannot create a
* second, stale page scrollbar.
*/
overflow: hidden;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Global document locking clips the authentication shell on short viewports

This applies overflow: hidden to html/body, and the new #root rule also hides overflow. LoginPrompt (web/src/components/LoginPrompt.tsx:116) is a full-height centered container without .app-scroll-y; when its form plus footer exceeds the visual viewport (landscape phone or opened keyboard), the overflow is unreachable. Scope the lock to the chat route, or give every pre-auth screen an explicit scroll owner.

Suggested fix:

html,
body {
    overflow-x: hidden;
    overflow-y: auto;
}

#root {
    overflow: visible;
}

html:has(.chat-scroll-y),
body:has(.chat-scroll-y),
html:has(.chat-scroll-y) #root {
    overflow: hidden;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9dd77d7. I restored the existing document scrolling behavior for non-chat routes and now apply overflow containment only while a .chat-scroll-y viewport is present, so short login/binding viewports remain reachable.

Comment thread web/src/index.css Outdated
}

.chat-scroll-content {
padding-inline: 0.125rem;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MINOR] Preserve padding when the touch scrollbar is overlay-only

scrollbar-gutter: stable both-edges does not reserve layout space for overlay scrollbars, which are common on touch browsers. The unconditional override here therefore changes the existing p-3 inset from 12px to 2px on those devices, leaving chat content almost flush with the screen edge. Keep p-3 as the fallback; only subtract padding when a nonzero classic gutter has actually been detected.

Suggested fix:

@media (hover: none) and (pointer: coarse) {
    .chat-scroll-y {
        scrollbar-gutter: stable both-edges;
    }

    /* Do not override .chat-scroll-content padding without a measured gutter. */
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9dd77d7. The chat viewport now measures the gutter actually reserved by the browser and subtracts only that amount. Overlay-scrollbar devices report a zero physical gutter and therefore keep the original 12px content padding.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • None.

Summary
Review mode: follow-up after new commits

No issues found in the latest full diff. The new commits address the prior document-locking and overlay-scrollbar findings. Residual risk: scrollbar-gutter and mobile viewport behavior remain browser-engine dependent, and this PR adds no automated browser coverage for those cases.

Testing
Not run (review automation; PR code was not executed). Suggested coverage: Playwright checks for chat-only document containment plus effective 12px side insets with both classic and overlay scrollbar configurations.

HAPI Bot

@tiann
tiann merged commit 01bffa3 into tiann:main Aug 1, 2026
4 checks passed
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