Real root cause of the blank mobile terminal (the FN-7692 remeasure guard did not
fix it and is reverted here). styles.css has a mobile-only reset
`@media (max-width: 768px) { * { max-width: 100% } }` to prevent horizontal
overflow. That universal selector also matches xterm's hidden character-measurement
subtree (`.xterm-helpers` / `.xterm-char-measure-element`). That subtree's containing
block (`.xterm-helpers`) is a 0x0 absolutely-positioned box, so `max-width: 100%`
resolves to `max-width: 0` and hard-caps xterm's character-cell measurement at 0.
FitAddon.fit() then proposes 0 columns/rows and `.xterm-screen` (plus the WebGL
canvas) collapses to 0x0 — the prompt streams in and is written into xterm's row DOM
but paints into a zero-size box, so the terminal is blank. Mobile-only, which is why
desktop always rendered fine.
Reproduced live via mobile emulation: `.xterm-char-measure-element` measured 0 while
an identical monospace span in the same container measured ~295px; `max-width: none`
on the measure element restored ~295px, and reopening the terminal with the exemption
active rendered the prompt with `.xterm-screen` sized 369x760. No amount of
remeasure/refit can fix this — the CSS re-caps the measurement to 0 every time — so
the FN-7692 CharSizeService guard is removed.
- Exempt `.xterm-helpers` / `.xterm-char-measure-element` from the mobile max-width
reset in styles.css (covers both TerminalModal and SessionTerminal)
- Revert the ineffective FN-7692 remeasure guard and its tests
- Update changeset (patch) and the docs/solutions write-up to the real root cause
Note: root cause + fix validated in the automation browser via mobile emulation
(393px, iPhone UA, forced touch), not a physical device.
Fusion-Task-Id: FN-7693
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.0 KiB
title, date, category, module, problem_type, component, applies_when, symptoms, root_cause, resolution_type, severity, related_components, tags
| title | date | category | module | problem_type | component | applies_when | symptoms | root_cause | resolution_type | severity | related_components | tags | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Mobile terminal renders blank: global `* { max-width: 100% }` collapses xterm's char measurement | 2026-07-08 | ui-bugs | packages/dashboard/app/styles.css | rendering | embedded_terminal | The standalone (TerminalModal) or task-session (SessionTerminal) terminal shows nothing on mobile even though the WebSocket says Connected and the prompt has arrived. |
|
mobile_universal_max_width_100pct_caps_xterm_char_measure_element_at_zero | css_exemption | high |
|
|
Mobile terminal renders blank: universal max-width: 100% collapses xterm's character measurement
Problem
On the mobile terminal layout the terminal opens, the WebSocket connects, the shell prompt data
streams in and is written into xterm's row DOM — but the terminal is visibly blank. It is NOT a
network, PTY, or login-shell latency problem (measured live: POST /terminal/sessions 3ms, WS first
prompt bytes ~215ms, desktop renders <1s).
Root cause
styles.css has a global mobile reset to prevent horizontal overflow:
@media (max-width: 768px) {
* { max-width: 100%; max-inline-size: 100%; }
}
This universal * { max-width: 100% } also matches xterm's hidden character-measurement subtree —
.xterm-helpers and its .xterm-char-measure-element. That subtree's containing block
(.xterm-helpers) is a 0x0 absolutely-positioned box, so max-width: 100% resolves to max-width: 0 and hard-caps the measurement element at 0 width. xterm's CharSizeService therefore reads a
0-width character cell, FitAddon.proposeDimensions() yields 0 columns/rows, and .xterm-screen (plus
the WebGL renderer canvas) collapses to 0x0 — the prompt is painted into a zero-size box.
Reproduced live via mobile emulation: .xterm-char-measure-element measured 0 while an identical
monospace span in the same .xterm container measured ~295px; setting max-width: none on the measure
element immediately restored ~295px, and reopening the terminal with the exemption active rendered the
prompt with .xterm-screen sized 369x760.
The bug is mobile-only because the reset is inside a max-width: 768px media query — which is
exactly why the terminal renders fine at desktop widths.
Why prior remeasure-based attempts failed
FN-7620/FN-7686 (and an initial FN-7693 attempt) tried to force xterm to remeasure/refit after mount.
That can never work here: the CSS re-caps the measurement element to 0 width on every remeasure, so
a resize, a font-size change, and a forced CharSizeService remeasure all still read 0. The fix must
remove the CSS cap, not re-run the measurement.
Fix
Exempt xterm's measurement subtree from the mobile universal reset (in the same @media block in
styles.css):
.xterm-helpers,
.xterm-helpers *,
.xterm-char-measure-element {
max-width: none !important;
max-inline-size: none !important;
}
.xterm-helpers is xterm's own class, so this covers both terminal surfaces (TerminalModal and
SessionTerminal) without per-component changes.
Verification
- Live: with the exemption active,
.xterm-char-measure-elementmeasures ~295px (was 0) and.xterm-screengets a real width (was 0x0), rendering the prompt on the mobile viewport. - Physical-device note: root cause and fix were reproduced/validated in the automation browser via mobile emulation (393px, iPhone UA, forced touch), not a physical iPhone. Confirm on a real device when possible.