What
client/src/styles/_global.scss:83-88 pins the app to 100vh:
body { overflow: hidden; }
#root {
min-width: 100vw;
min-height: 100vh;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.App { height: 100%; overflow: auto; }
On iOS Safari 100vh resolves to the large viewport — the height the page
would have if the URL bar and toolbar were hidden. With the browser chrome
actually on screen (the normal state on load) the real visible area is roughly
60–110 px shorter. So the bottom of #root sits below the fold.
Every escape hatch is closed:
body { overflow: hidden } — the page itself cannot scroll to reveal it.
#root { overflow: hidden } — same.
.App is height: 100% of a 100vh parent, so its own bottom edge — where
the sticky footer lives — is off-screen too, and scrolling .App only moves
its contents, never its bottom edge.
The result is the exact failure mode of #246: the footer is present in the DOM,
invisible, and unreachable by scrolling. #246 was fixed for the flex-shrink
cause (flex-shrink: 0 on .v-footer); this is the same symptom arriving by a
different route, and only on iOS.
Why this wasn't caught
Desktop Chrome has static browser chrome, so 100vh and the visible height are
identical and the bug cannot reproduce. I swept 320–1440 px in a real viewport
and found nothing here — the trigger is iOS's dynamic toolbar, not width.
Not confirmed on hardware. This is read from the CSS and from documented
iOS Safari viewport behaviour. It needs a real iPhone to verify, which is why
it is filed rather than fixed blind.
Fix
Progressive enhancement — browsers that don't know dvh ignore the second
declaration:
#root {
height: 100vh;
height: 100dvh;
min-height: 100vh;
min-height: 100dvh;
}
dvh tracks the dynamic viewport, shrinking and growing as the toolbar
slides. Supported in iOS Safari 15.4+ and every current desktop browser.
While here: width: 100vw includes the scrollbar gutter on desktop, which
forces a few px of horizontal overflow. width: 100% is the correct value and
costs nothing.
Acceptance
On a real iPhone, at first paint with the URL bar visible, the footer is
reachable by scrolling on /live (the tallest page) and /nodes.
What
client/src/styles/_global.scss:83-88pins the app to100vh:On iOS Safari
100vhresolves to the large viewport — the height the pagewould have if the URL bar and toolbar were hidden. With the browser chrome
actually on screen (the normal state on load) the real visible area is roughly
60–110 px shorter. So the bottom of
#rootsits below the fold.Every escape hatch is closed:
body { overflow: hidden }— the page itself cannot scroll to reveal it.#root { overflow: hidden }— same..Appisheight: 100%of a100vhparent, so its own bottom edge — wherethe sticky footer lives — is off-screen too, and scrolling
.Apponly movesits contents, never its bottom edge.
The result is the exact failure mode of #246: the footer is present in the DOM,
invisible, and unreachable by scrolling. #246 was fixed for the flex-shrink
cause (
flex-shrink: 0on.v-footer); this is the same symptom arriving by adifferent route, and only on iOS.
Why this wasn't caught
Desktop Chrome has static browser chrome, so
100vhand the visible height areidentical and the bug cannot reproduce. I swept 320–1440 px in a real viewport
and found nothing here — the trigger is iOS's dynamic toolbar, not width.
Not confirmed on hardware. This is read from the CSS and from documented
iOS Safari viewport behaviour. It needs a real iPhone to verify, which is why
it is filed rather than fixed blind.
Fix
Progressive enhancement — browsers that don't know
dvhignore the seconddeclaration:
dvhtracks the dynamic viewport, shrinking and growing as the toolbarslides. Supported in iOS Safari 15.4+ and every current desktop browser.
While here:
width: 100vwincludes the scrollbar gutter on desktop, whichforces a few px of horizontal overflow.
width: 100%is the correct value andcosts nothing.
Acceptance
On a real iPhone, at first paint with the URL bar visible, the footer is
reachable by scrolling on
/live(the tallest page) and/nodes.