diff --git a/src/SharpClient.UI/wwwroot/app.css b/src/SharpClient.UI/wwwroot/app.css index fe8ac03..ed7781f 100644 --- a/src/SharpClient.UI/wwwroot/app.css +++ b/src/SharpClient.UI/wwwroot/app.css @@ -74,12 +74,14 @@ body { /* ── OutputView component classes (.sc-output / .sc-line) ──────── */ .sc-output { display: block; - /* Hold a floor of --sc-cols character columns (set by measureGrid alongside --out-fs). On a - screen too narrow to fit them at the minimum font, the output scrolls horizontally instead of - wrapping the server's NAWS-width lines — so what the player sees matches what the server wrapped - to. font-size must equal the line font so 1ch is the real column width. */ + /* Hold a floor of --sc-cols character columns. The track width is published in pixels by + measureGrid as --sc-cols-width, measured from a real glyph run on the SAME basis the font was + fitted to — NOT the CSS `ch` unit, whose single-glyph rounding ran ~2px wider than the fit and + produced a spurious horizontal scrollbar even when the columns fit. In the fitting case the + track stays inside the box, so lines wrap at the column edge with no scroll; only on a screen + too narrow to fit the columns at the minimum font does it exceed the box and scroll. */ font-size: var(--out-fs); - min-width: calc(var(--sc-cols, 0) * 1ch); + min-width: var(--sc-cols-width, 0px); } .sc-line { diff --git a/src/SharpClient.UI/wwwroot/sc-interop.js b/src/SharpClient.UI/wwwroot/sc-interop.js index 7d2ca49..d5519da 100644 --- a/src/SharpClient.UI/wwwroot/sc-interop.js +++ b/src/SharpClient.UI/wwwroot/sc-interop.js @@ -143,8 +143,17 @@ export function measureGrid(element, targetCols, minFont, maxFont) { cols = clampGrid(Math.floor(contentW / (advanceRatio * fontPx))); } + // Publish the column-track width in PIXELS, measured on the same basis the font was fitted to + // (a real run of `cols` glyphs). The CSS `ch` unit can't be used for the track: its single-glyph + // advance rounds a couple px wider than this averaged run, which pushed `cols * 1ch` past the + // content box and produced a spurious horizontal scrollbar even though the columns fit. Measured + // px keeps the track <= the box in the fitting case (no scroll, lines wrap at the column edge) and + // only exceeds it when the screen genuinely can't fit `cols` at the min font (then it scrolls). + const trackW = runWidth(fontPx, '0'.repeat(cols)); + element.style.setProperty('--out-fs', fontPx + 'px'); element.style.setProperty('--sc-cols', String(cols)); + element.style.setProperty('--sc-cols-width', trackW + 'px'); return { cols, rows: clampGrid(Math.floor(contentH / (lineRatio * fontPx))) }; }