mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-12 10:40:33 +00:00
3acd802588
The mobile .messages-inner rule used overflow-x:hidden, which per the CSS overflow spec coerces overflow-y from visible to auto — turning the inner into a scroll container. A scroll container's min-height:auto resolves to 0, so the inner (a flex-shrink:1 item inside the .messages column flexbox) collapsed to the viewport height instead of growing to its content. The transcript then overflowed the clipped inner rather than the .messages scroller, leaving nothing to scroll and pinning scrollTop at 0 — every open/send/receive stranded mobile users at the top with no way to scroll down. Fix: overflow-x:clip suppresses horizontal overflow (the original #4583/#4553 intent) WITHOUT coercing overflow-y or creating a scroll container, so min-height:auto stays min-content and the inner grows to full height. Verified empirically via headless Chrome mobile emulation (390x844, mobile=true): scrollableDelta 0 -> 7746; open/send/receive all land at bottom; mid-scroll position preserved across re-render. Desktop unaffected. Updated #4553 test (clip satisfies its horizontal-pan goal) + added dedicated
76 lines
3.6 KiB
Python
76 lines
3.6 KiB
Python
"""Regression test for #4856: mobile transcript collapses and won't scroll.
|
|
|
|
Root cause (proven empirically via headless Chrome mobile emulation):
|
|
|
|
The mobile `.messages-inner` rule carried `overflow-x:hidden` (added in the
|
|
#4583/#4584 batch, v0.51.576 — the user's bisected "first broken" version).
|
|
Per the CSS overflow spec, when one axis is `hidden` and the other is
|
|
`visible`, the `visible` axis is coerced to `auto`. So `overflow-x:hidden`
|
|
silently turned `overflow-y` into `auto`, making `.messages-inner` a SCROLL
|
|
CONTAINER.
|
|
|
|
A scroll container's `min-height:auto` resolves to `0` (not `min-content`).
|
|
`.messages-inner` is a flex item (default `flex-shrink:1`) inside the
|
|
`.messages` column flexbox, so with min-height 0 it collapsed to the
|
|
scroller's height (~681px) instead of growing to its content (~8251px). The
|
|
transcript then overflowed the INNER (which clipped it) rather than the
|
|
`.messages` scroller — so the scroller had nothing to scroll, `scrollTop`
|
|
was pinned at 0, and every open/send/receive left the reader stuck at the
|
|
top with no way to scroll down. Desktop escaped the collapse; mobile didn't.
|
|
|
|
Fix: `overflow-x:clip` clips horizontal overflow (the original #4553/#4583
|
|
intent) WITHOUT coercing `overflow-y` or creating a scroll container, so
|
|
`min-height:auto` stays `min-content` and the inner grows to its full height.
|
|
|
|
These are source-level guards; the runtime collapse is layout/viewport
|
|
specific and not reproducible in headless CI without a full browser.
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
CSS = (Path(__file__).resolve().parent.parent / "static" / "style.css").read_text(encoding="utf-8")
|
|
|
|
|
|
def _mobile_messages_inner_rule() -> str:
|
|
media = re.search(r"@media\(max-width:640px\)\{", CSS)
|
|
assert media, "@media(max-width:640px) block not found"
|
|
window = CSS[media.start(): media.start() + 8000]
|
|
m = re.search(r"\.messages-inner\{([^}]*)\}", window)
|
|
assert m, ".messages-inner rule not found in mobile media block"
|
|
return m.group(0)
|
|
|
|
|
|
def test_mobile_inner_does_not_become_scroll_container():
|
|
"""overflow-x:hidden coerces overflow-y:auto, making the inner a scroll
|
|
container whose min-height:auto resolves to 0 — the #4856 collapse. The
|
|
mobile inner must use overflow-x:clip instead."""
|
|
rule = _mobile_messages_inner_rule()
|
|
assert "overflow-x:clip" in rule, (
|
|
"mobile .messages-inner must use overflow-x:clip so it clips horizontal "
|
|
"overflow without becoming an unscrollable scroll container (#4856)"
|
|
)
|
|
assert "overflow-x:hidden" not in rule, (
|
|
"mobile .messages-inner must NOT use overflow-x:hidden — it coerces "
|
|
"overflow-y to auto and collapses the transcript (#4856 regression)"
|
|
)
|
|
|
|
|
|
def test_mobile_inner_must_not_set_overflow_y_auto_or_scroll():
|
|
"""Belt-and-suspenders: an explicit overflow-y:auto/scroll on the inner
|
|
would reintroduce the scroll-container collapse even with overflow-x:clip."""
|
|
rule = _mobile_messages_inner_rule()
|
|
assert "overflow-y:auto" not in rule and "overflow-y:scroll" not in rule, (
|
|
"mobile .messages-inner must not be a scroll container on the Y axis "
|
|
"(would re-trigger the #4856 min-height:0 flex collapse)"
|
|
)
|
|
|
|
|
|
def test_messages_scroller_keeps_overflow_y_auto():
|
|
"""The actual scroller is .messages, not .messages-inner — confirm it
|
|
still owns vertical scrolling so the transcript scrolls there."""
|
|
m = re.search(r"\.messages\{[^}]*\}", CSS)
|
|
assert m, ".messages rule not found"
|
|
assert "overflow-y:auto" in m.group(0), (
|
|
".messages must remain the overflow-y:auto scroll container (#4856)"
|
|
)
|