fix(footer): offset sticky-footer's left edge past the sidebar

The "white bar" was the footer's near-white background painting
over the bottom of the sidebar. The footer is fixed at body level
with ``left: 0; right: 0`` so it spans the full viewport — its
``rgba(255, 255, 255, 0.97)`` background renders as essentially
white over the sidebar's ``rgb(240, 242, 246)`` gray, producing a
visibly different strip at the bottom of the sidebar (this is what
the diagnostic GREEN tint marked as ``stAppViewContainer``-shaped
because that is the element directly behind it).

Pixel-sampled the bottom row to confirm:
  y=860 over sidebar  →  (240, 242, 246)  (gray)
  y=870 over sidebar  →  (255, 255, 255)  (footer-painted white)

Fix: in the iframe JS that mounts the footer on ``<body>``, measure
``[data-testid="stSidebar"].getBoundingClientRect().right`` and set
the footer's (and help popover's) ``left`` to that offset with
``setProperty(..., 'important')`` so it beats the ``left:0!important``
fallback in CSS. A ``ResizeObserver`` on the sidebar plus a
``window.resize`` listener keep the offset in sync when the sidebar
collapses or expands.

Sidebar collapsed (width 0 or off-screen) clamps to 0 → footer goes
flush-left as before. Also dropped the no-op ``min-height`` on the
view container from the previous attempt; ``stAppViewContainer`` is
transparent, so stretching it never painted anything.

Verified by injecting the same offset on the live page: bottom row
at y=890 is now ``(240,242,246)`` over the sidebar and only turns
white at x=255 where the content area begins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 22:52:02 +00:00
parent 61e63913cb
commit c942b8aa19

View File

@@ -628,15 +628,6 @@ def render_sticky_footer() -> None:
st.markdown(
"""
<style>
/* The view container is the element whose background paints the
strip between the last piece of content and the fixed footer
overlay (confirmed via colored-tag diagnostic). ``.stApp`` carries
``zoom: 0.85`` so 100vh renders at 85% visually — divide by 0.85
so the container spans the full visible viewport and there's no
gap for its own background to show through as a "white bar". */
[data-testid="stAppViewContainer"] {
min-height: calc(100vh / 0.85) !important;
}
[data-testid="stAppViewBlockContainer"] {
/* Reserve room for the fixed footer overlay (footer min-height
32px + 0.25rem * 2 padding ≈ 2rem). */
@@ -880,6 +871,37 @@ a[data-testid="stPageLink-NavLink"][href*="close"] {
doc.body.appendChild(div);
doc.body.appendChild(pop);
// Push the footer's left edge to start at the sidebar's right
// edge so its near-white background doesn't paint over the
// sidebar's gray and read as a visible "white bar" along the
// bottom of the sidebar. Same offset for the help popover.
// Re-measure whenever the sidebar resizes (collapse/expand)
// so the offset tracks the live layout.
var sb = doc.querySelector('[data-testid="stSidebar"]');
function applyOffset() {{
var off = 0;
if (sb) {{
var r = sb.getBoundingClientRect();
// If the sidebar is collapsed it can have width 0 OR be
// pushed off-screen (negative right). Clamp to 0 so the
// footer goes flush-left in that case.
off = Math.max(0, Math.round(r.right));
}}
// ``!important`` because the CSS rule for ``left`` is itself
// ``!important`` and would otherwise win over plain inline.
div.style.setProperty('left', off + 'px', 'important');
pop.style.setProperty('left', (off + 12) + 'px', 'important');
}}
applyOffset();
if (sb && 'ResizeObserver' in window) {{
try {{ new ResizeObserver(applyOffset).observe(sb); }} catch (e) {{}}
}}
// Also re-measure on window resize as a belt-and-suspenders
// — handles viewport changes that don't trigger the sidebar's
// own resize event.
var win = doc.defaultView || window.parent || window;
try {{ win.addEventListener('resize', applyOffset); }} catch (e) {{}}
}}
try {{
build(window.parent.document);