Fix docs sidebar navigation scroll targeting with lazy-loaded images

This commit is contained in:
Broque Thomas 2026-03-14 11:16:26 -07:00
parent c3eecc88ad
commit fead6db379
2 changed files with 45 additions and 16 deletions

View file

@ -2247,15 +2247,31 @@ function initializeDocsPage() {
suppressScrollSpy._timer = setTimeout(() => { _scrollSpySuppressed = false; }, 800); suppressScrollSpy._timer = setTimeout(() => { _scrollSpySuppressed = false; }, 800);
} }
// Helper: get element offset relative to a scrollable ancestor // Scroll a target element into view within the docs-content container.
function getOffsetRelativeTo(el, ancestor) { // Uses manual offsetTop calculation instead of scrollIntoView to avoid
let offset = 0; // misalignment caused by lazy-loaded images that haven't reserved height yet.
let current = el; // Does an initial scroll, then a correction after images near the target load.
while (current && current !== ancestor) { function scrollDocTarget(target) {
offset += current.offsetTop; if (!target || !docsContent) return;
current = current.offsetParent; suppressScrollSpy();
function calcOffset(el) {
let offset = 0;
let current = el;
while (current && current !== docsContent) {
offset += current.offsetTop;
current = current.offsetParent;
}
return offset;
} }
return offset;
// Initial scroll
docsContent.scrollTop = calcOffset(target);
// Correction pass after lazy images near the target have had time to load
// and shift layout. Two passes cover most reflow scenarios.
setTimeout(() => { docsContent.scrollTop = calcOffset(target); }, 150);
setTimeout(() => { docsContent.scrollTop = calcOffset(target); }, 500);
} }
// Section title click → expand/collapse children + scroll // Section title click → expand/collapse children + scroll
@ -2275,10 +2291,9 @@ function initializeDocsPage() {
if (children) children.classList.add('expanded'); if (children) children.classList.add('expanded');
} }
// Scroll to section (suppress scroll spy so it doesn't fight) // Scroll to section
suppressScrollSpy();
const target = document.getElementById('docs-' + sectionId); const target = document.getElementById('docs-' + sectionId);
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' }); scrollDocTarget(target);
}); });
}); });
@ -2290,9 +2305,8 @@ function initializeDocsPage() {
child.classList.add('active'); child.classList.add('active');
// Keep parent section expanded // Keep parent section expanded
suppressScrollSpy();
const target = document.getElementById(child.dataset.target); const target = document.getElementById(child.dataset.target);
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' }); scrollDocTarget(target);
}); });
}); });
@ -2386,11 +2400,23 @@ function initializeDocsPage() {
function navigateToDocsSection(sectionId) { function navigateToDocsSection(sectionId) {
// Switch to help page // Switch to help page
if (typeof navigateToPage === 'function') navigateToPage('help'); if (typeof navigateToPage === 'function') navigateToPage('help');
// Wait for docs to initialize // Wait for docs to initialize, then use manual scroll with correction passes
setTimeout(() => { setTimeout(() => {
const target = document.getElementById(sectionId); const target = document.getElementById(sectionId);
if (target) { const docsContent = document.getElementById('docs-content');
target.scrollIntoView({ behavior: 'smooth', block: 'start' }); if (target && docsContent) {
function calcOffset(el) {
let offset = 0;
let current = el;
while (current && current !== docsContent) {
offset += current.offsetTop;
current = current.offsetParent;
}
return offset;
}
docsContent.scrollTop = calcOffset(target);
setTimeout(() => { docsContent.scrollTop = calcOffset(target); }, 150);
setTimeout(() => { docsContent.scrollTop = calcOffset(target); }, 500);
} }
}, 300); }, 300);
} }

View file

@ -35863,6 +35863,7 @@ tr.tag-diff-same {
/* Main content */ /* Main content */
.docs-content { .docs-content {
flex: 1; flex: 1;
position: relative;
overflow-y: auto; overflow-y: auto;
padding: 40px 48px; padding: 40px 48px;
scroll-behavior: smooth; scroll-behavior: smooth;
@ -36108,6 +36109,8 @@ tr.tag-diff-same {
.docs-screenshot { .docs-screenshot {
width: 100%; width: 100%;
max-width: 800px; max-width: 800px;
aspect-ratio: 16 / 9;
object-fit: contain;
border-radius: 10px; border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);