Stop the table being drawn from a measurement of a bar that isn't there
The felt is sized from --feltRoomPx, which actionBar.js publishes from the bar's real height, because the bar is fixed to the bottom and grows with the hand so nothing else can know how much window is left. That measurement is right. What it was measuring was not. ActionBar.mount() called watchHeight() before render(), and the bar ships `<div id="actionBar" hidden>`. So the first publish measured a bar that was not there yet and published 0px — not "I don't know" but "the bar takes none of the window", which is the one answer that makes the felt draw itself too big. Traced on a cold load, nine-handed: t=181ms --actionBarHeight 0px bar hidden, 0 tall t=186ms --feltRoomPx 721px t=1056ms --actionBarHeight 151px bar visible, 151 tall — ResizeObserver t=1059ms --feltRoomPx 570px The observer does come round on its own once `hidden` comes off, but a frame later at best, and with nine seats to lay out it was 875ms behind. What a dealer saw at 360x640 was a table drawn 336x504 and collapsing to 336x374 after it was on screen and readable: 130px of felt with every seat on it. 1280x900 lost 13px the same way. Two rules, separate on purpose. publish() now declines rather than guessing while the bar is hidden and not a rail — a rail still publishes its honest zero, because it is a real bar that has moved out of the way. And mount() publishes once render() has given it something to measure. That leaves the frame before any of it, which is real: the scripts are at the end of the body and the table is laid out inside DOMContentLoaded, so the browser has painted by the time --feltRoomPx exists. The fallback there was `100vh` — the worst guess available, since it says the whole window is free. It is now the same guess two other rules in this file already make, 9rem for the bar plus 7rem for what sits above and below, which lands 10px over the truth at 360x640; and it is a ceiling, so over is a small shrink rather than a seat behind the bar. Measured after, on both phones: one draw, no jump, and a layout-shift score of 0 where the felt used to move 130px. 1362 tests pass, 8 of them new — 5 fail against the old code. One existing test pinned the literal fallback string; its claim is about the cap being the measured room, and it now says that. The sweep is clean across 428 audits; contrast unchanged. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -140,7 +140,18 @@ describe("what stops the oval", () => {
|
||||
// The oval is a preference and the room is a fact. Whatever shape is asked for
|
||||
// above, the felt gives way to the measurement rather than the other way round,
|
||||
// because the thing on the other side of the cap is a seat behind the action bar.
|
||||
assert.equal(phoneRule, "var(--feltRoomPx, 100vh)");
|
||||
assert.match(phoneRule, /^var\(--feltRoomPx,/,
|
||||
"something other than the measured room decides how tall the felt may be");
|
||||
});
|
||||
|
||||
test("and what it falls back on is a near guess rather than the whole window", () => {
|
||||
// The fallback is only ever used for the frame before actionBar.js has measured
|
||||
// anything — but that frame is one a dealer sees, because the scripts run at the
|
||||
// end of the body. `100vh` was what stood here, and it says the whole window is
|
||||
// free: measured at 360x640 nine-handed, the table came up 336x504 and dropped to
|
||||
// 336x374 as soon as the bar was measured. See whatTheFeltIsToldFirst.
|
||||
assert.doesNotMatch(phoneRule, /var\(--feltRoomPx,\s*100vh\)/);
|
||||
assert.match(phoneRule, /var\(--actionBarHeight, 9rem\)/);
|
||||
});
|
||||
|
||||
test("and it is not floored, however tempting that is", () => {
|
||||
|
||||
Reference in New Issue
Block a user