test(home): outline every fixed/sticky element to find the white bar
User reports: TEST #3 marker sits at the true bottom of the home page's main content, but when scrolled the test text "goes behind" an opaque white bar — confirming the bar is fixed/sticky (overlays scrolling content). Our CSS only declares ONE fixed element near the bottom (``#datatools-sticky-footer``), which the user already ruled out. So something else — Streamlit native chrome, a third- party widget, or a fixed element we haven't enumerated — is overlaying the content. Inject a small diagnostic iframe whose JS, running against the parent document, walks every element on the page and outlines each ``position: fixed`` or ``position: sticky`` node with a distinct color + a top-left label showing ``tagName#id[data-testid] pos=… h=…px bg=…``. Re-runs after initial paint, on a couple of delays (for late-mounting components), and on every scroll. This is read-only — no DOM mutations beyond outline styles and labels — so it's safe to ship even if I miss removing it. The user can now visually identify which colored box is the offending white bar and report its label. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -289,16 +289,87 @@ def _home_page() -> None:
|
|||||||
key_namespace=name,
|
key_namespace=name,
|
||||||
)
|
)
|
||||||
|
|
||||||
# TEMP: visible marker at the very end of the home page's main
|
# TEMP: end-of-content marker — confirmed at the true bottom of
|
||||||
# content. Used to locate the "white bar" the user wants removed.
|
# the home page's main content. The user reports content scrolls
|
||||||
# If this red banner lines up with the offending white strip when
|
# *behind* the offending white bar, so the bar is fixed-positioned.
|
||||||
# scrolled to the bottom, the strip is something rendered right
|
# Only ``#datatools-sticky-footer`` is fixed at the bottom per
|
||||||
# here at the tail of ``stAppViewBlockContainer``.
|
# our CSS, but the user already confirmed the sticky footer is
|
||||||
|
# NOT the offending bar. So there's a fixed element we haven't
|
||||||
|
# accounted for. The JS below outlines EVERY fixed/sticky element
|
||||||
|
# in the parent document with a labelled colored border so we can
|
||||||
|
# see exactly what's overlaying scrolled content.
|
||||||
st.markdown(
|
st.markdown(
|
||||||
'<div style="background:#ffe0e0;border:2px dashed #b00020;'
|
'<div style="background:#ffe0e0;border:2px dashed #b00020;'
|
||||||
'color:#b00020;font-weight:700;font-size:13px;text-align:center;'
|
'color:#b00020;font-weight:700;font-size:13px;text-align:center;'
|
||||||
'padding:8px 12px;margin:4px 0;font-family:system-ui,sans-serif;">'
|
'padding:8px 12px;margin:4px 0;font-family:system-ui,sans-serif;">'
|
||||||
'◀ CLAUDE TEST #3 — END OF MAIN CONTENT — IS THIS THE WHITE BAR? ▶'
|
'◀ CLAUDE TEST #3 — END OF MAIN CONTENT ▶'
|
||||||
'</div>',
|
'</div>',
|
||||||
unsafe_allow_html=True,
|
unsafe_allow_html=True,
|
||||||
)
|
)
|
||||||
|
st.iframe(
|
||||||
|
"""
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
function outlineFixed() {
|
||||||
|
var doc = window.parent.document;
|
||||||
|
if (!doc) return;
|
||||||
|
// Clear previous outlines + labels so reruns don't stack.
|
||||||
|
doc.querySelectorAll('[data-claude-outline-label]').forEach(function (n) {
|
||||||
|
n.remove();
|
||||||
|
});
|
||||||
|
doc.querySelectorAll('[data-claude-outlined]').forEach(function (el) {
|
||||||
|
el.style.outline = '';
|
||||||
|
el.style.outlineOffset = '';
|
||||||
|
el.removeAttribute('data-claude-outlined');
|
||||||
|
});
|
||||||
|
var palette = ['#e6194b', '#3cb44b', '#4363d8', '#f58231', '#911eb4',
|
||||||
|
'#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080'];
|
||||||
|
var idx = 0;
|
||||||
|
doc.querySelectorAll('*').forEach(function (el) {
|
||||||
|
var cs = window.parent.getComputedStyle(el);
|
||||||
|
if (cs.position !== 'fixed' && cs.position !== 'sticky') return;
|
||||||
|
var rect = el.getBoundingClientRect();
|
||||||
|
// Skip zero-size and off-screen-only items.
|
||||||
|
if (rect.width < 2 || rect.height < 2) return;
|
||||||
|
var color = palette[idx % palette.length];
|
||||||
|
idx += 1;
|
||||||
|
el.style.outline = '3px solid ' + color;
|
||||||
|
el.style.outlineOffset = '-3px';
|
||||||
|
el.setAttribute('data-claude-outlined', '1');
|
||||||
|
// Label pinned to the element's top-left.
|
||||||
|
var label = doc.createElement('div');
|
||||||
|
label.setAttribute('data-claude-outline-label', '1');
|
||||||
|
var name = el.tagName.toLowerCase()
|
||||||
|
+ (el.id ? '#' + el.id : '')
|
||||||
|
+ (el.getAttribute('data-testid')
|
||||||
|
? '[' + el.getAttribute('data-testid') + ']' : '')
|
||||||
|
+ ' pos=' + cs.position
|
||||||
|
+ ' h=' + Math.round(rect.height) + 'px'
|
||||||
|
+ ' bg=' + cs.backgroundColor;
|
||||||
|
label.textContent = name;
|
||||||
|
label.style.cssText =
|
||||||
|
'position:fixed;left:' + Math.max(0, rect.left) + 'px;'
|
||||||
|
+ 'top:' + Math.max(0, rect.top - 18) + 'px;'
|
||||||
|
+ 'background:' + color + ';color:#fff;'
|
||||||
|
+ 'font:11px/1.2 ui-monospace,monospace;'
|
||||||
|
+ 'padding:2px 5px;border-radius:3px;'
|
||||||
|
+ 'z-index:2147483647;pointer-events:none;'
|
||||||
|
+ 'white-space:nowrap;max-width:90vw;overflow:hidden;'
|
||||||
|
+ 'text-overflow:ellipsis;';
|
||||||
|
doc.body.appendChild(label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Run after initial paint and again after Streamlit's component
|
||||||
|
// iframes settle.
|
||||||
|
setTimeout(outlineFixed, 400);
|
||||||
|
setTimeout(outlineFixed, 1500);
|
||||||
|
setTimeout(outlineFixed, 3500);
|
||||||
|
// Re-run on scroll so labels track the current viewport state.
|
||||||
|
window.parent.addEventListener('scroll', function () {
|
||||||
|
setTimeout(outlineFixed, 50);
|
||||||
|
}, true);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
""",
|
||||||
|
height=1,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user