Skip to content

Commit c8433fe

Browse files
committed
Fix the heading scroll position
1 parent c38321c commit c8433fe

File tree

5 files changed

+80
-2
lines changed

5 files changed

+80
-2
lines changed

src/components/ScrollOffsetFix.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { useEffect } from 'react';
2+
import { initScrollOffset } from '../lib/scrollOffset';
3+
4+
export function ScrollOffsetFix() {
5+
useEffect(() => {
6+
initScrollOffset();
7+
}, []);
8+
9+
return null; // This component doesn't render anything
10+
}
11+
12+
export default ScrollOffsetFix;

src/css/custom.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@
3030

3131
// Navbar customization
3232
--ifm-navbar-height: 122px;
33+
// Total navbar height including tabs and padding for accurate scroll positioning
34+
--navbar-total-height: 140px;
3335

3436
@media (max-width: 996px) {
3537
--ifm-navbar-height: 80px;
38+
--navbar-total-height: 80px; // No tabs on mobile
3639
}
3740

3841
// Doc Sidebar

src/lib/scrollOffset.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export function getNavbarHeight(): number {
2+
if (typeof window === "undefined") return 140;
3+
4+
const navbar = document.querySelector("nav.navbar");
5+
if (!navbar) return 140;
6+
7+
const height = navbar.getBoundingClientRect().height;
8+
return height;
9+
}
10+
11+
function scrollToElementWithOffset(element: Element): void {
12+
const navbarHeight = getNavbarHeight();
13+
const elementRect = element.getBoundingClientRect();
14+
const absoluteElementTop = elementRect.top + window.pageYOffset;
15+
const targetScrollTop = absoluteElementTop - navbarHeight - 16;
16+
17+
window.scrollTo({
18+
top: targetScrollTop,
19+
behavior: "smooth",
20+
});
21+
}
22+
23+
function handleHashNavigation(): void {
24+
if (typeof window === "undefined") return;
25+
26+
const hash = window.location.hash;
27+
if (!hash) return;
28+
29+
const targetId = hash.substring(1);
30+
const targetElement = document.getElementById(targetId);
31+
32+
if (targetElement) {
33+
setTimeout(() => {
34+
scrollToElementWithOffset(targetElement);
35+
}, 100);
36+
}
37+
}
38+
39+
function handleHashLinkClick(event: Event): void {
40+
const target = event.target as HTMLElement;
41+
const link = target.closest('a[href^="#"]') as HTMLAnchorElement;
42+
43+
if (!link || !link.hash) return;
44+
45+
const targetId = link.hash.substring(1);
46+
const targetElement = document.getElementById(targetId);
47+
48+
if (targetElement) {
49+
event.preventDefault();
50+
history.pushState(null, "", link.hash);
51+
scrollToElementWithOffset(targetElement);
52+
}
53+
}
54+
55+
export function initScrollOffset(): void {
56+
if (typeof window === "undefined") return;
57+
58+
setTimeout(handleHashNavigation, 100);
59+
setTimeout(handleHashNavigation, 500);
60+
window.addEventListener("hashchange", handleHashNavigation);
61+
document.addEventListener("click", handleHashLinkClick);
62+
}
63+

src/theme/Layout/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ErrorPageContent from "@theme/ErrorPageContent";
1313
import supertokens from "supertokens-website";
1414
import type { Props } from "@theme/Layout";
1515
import styles from "./styles.module.css";
16+
import ScrollOffsetFix from "@site/src/components/ScrollOffsetFix";
1617

1718
if (typeof window !== "undefined") {
1819
const isProdEnv =
@@ -51,6 +52,7 @@ export default function Layout(props: Props): JSX.Element {
5152
return (
5253
<LayoutProvider>
5354
<PageMetadata title={title} description={description} />
55+
<ScrollOffsetFix />
5456

5557
<SkipToContent />
5658

src/theme/Root.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ export default function Root({ children }: { children: React.ReactNode }) {
1818
init();
1919
}, []);
2020

21-
useLayoutEffect(() => {}, []);
22-
2321
useEffect(() => {
2422
trackPageView();
2523
}, [pathname]);

0 commit comments

Comments
 (0)