@@ -10,7 +10,6 @@ import links from "@data/links.json";
1010
1111<section
1212 id =" navbar"
13- class =" fixed top-0 z-50 transition-transform duration-300 transform-gpu w-full"
1413>
1514 <div
1615 class =" container max-w-[1150px] mx-auto px-6 py-2 mt-1 lg:p-2 lg:mt-6 flex items-center justify-between relative z-40 bg-white/80 rounded-full backdrop-blur-md shadow-lg"
@@ -47,28 +46,119 @@ import links from "@data/links.json";
4746</section >
4847<Search />
4948
49+ <style >
50+ #navbar {
51+ position: fixed;
52+ top: 0;
53+ width: 100%;
54+ z-index: 1000;
55+ transition: transform 0.3s ease-in-out;
56+ transform: translateY(0);
57+ }
58+ </style >
5059<script >
51- document.addEventListener("DOMContentLoaded", () => {
52- let prevScrollPos = window.pageYOffset;
60+ document.addEventListener("DOMContentLoaded", function() {
5361 const navbar = document.getElementById("navbar") as HTMLElement;
62+ if (!navbar) return;
5463
55- window.addEventListener("scroll", () => {
56- let currentScrollPos = window.pageYOffset;
57- if (prevScrollPos > currentScrollPos) {
64+ let prevScrollPos = window.pageYOffset || document.documentElement.scrollTop;
65+ let ticking = false;
66+ let isVisible = true;
67+
68+ // Ensure navbar is visible initially
69+ navbar.style.transform = "translateY(0)";
70+ navbar.style.transition = "transform 0.3s ease-in-out";
71+
72+ function updateNavbar() {
73+ // Handle iOS bounce - scroll position can be negative during bounce
74+ const rawScrollPos = window.pageYOffset || document.documentElement.scrollTop;
75+ const currentScrollPos = Math.max(0, rawScrollPos);
76+
77+ // Show navbar immediately if we're bouncing above the page (negative scroll)
78+ // or if we're very close to the top
79+ if (rawScrollPos <= 0 || currentScrollPos <= 50) {
80+ if (!isVisible) {
81+ navbar.style.transform = "translateY(0)";
82+ isVisible = true;
83+ }
84+ prevScrollPos = currentScrollPos;
85+ ticking = false;
86+ return;
87+ }
88+
89+ const documentHeight = document.documentElement.scrollHeight;
90+ const windowHeight = window.innerHeight;
91+
92+ // Don't hide navbar when at the very bottom
93+ if (currentScrollPos + windowHeight >= documentHeight - 50) {
94+ if (!isVisible) {
95+ navbar.style.transform = "translateY(0)";
96+ isVisible = true;
97+ }
98+ prevScrollPos = currentScrollPos;
99+ ticking = false;
100+ return;
101+ }
102+
103+ // Only update if scroll difference is significant
104+ const scrollDiff = Math.abs(currentScrollPos - prevScrollPos);
105+ if (scrollDiff < 3) {
106+ ticking = false;
107+ return;
108+ }
109+
110+ // Show navbar when scrolling up, hide when scrolling down
111+ if (prevScrollPos > currentScrollPos && !isVisible) {
58112 navbar.style.transform = "translateY(0)";
59- } else {
113+ isVisible = true;
114+ } else if (prevScrollPos < currentScrollPos && isVisible && currentScrollPos > 100) {
60115 navbar.style.transform = "translateY(-100%)";
116+ isVisible = false;
61117 }
118+
62119 prevScrollPos = currentScrollPos;
63- });
120+ ticking = false;
121+ }
64122
65- navbar.addEventListener("focusin", () => {
66- navbar.style.transform = "translateY(0)";
67- });
123+ function requestTick() {
124+ if (!ticking) {
125+ requestAnimationFrame(updateNavbar);
126+ ticking = true;
127+ }
128+ }
68129
69- navbar.addEventListener("focusout", () => {
70- if (window.pageYOffset > 100) {
71- navbar.style.transform = "translateY(-100%)";
130+ // Use passive listener for better performance on mobile
131+ window.addEventListener("scroll", requestTick, { passive: true });
132+
133+ // Additional safety check specifically for iOS bounce recovery
134+ let bounceCheckTimeout: any = null;
135+
136+ window.addEventListener("scroll", function() {
137+ // Clear any existing timeout
138+ if (bounceCheckTimeout) {
139+ clearTimeout(bounceCheckTimeout);
140+ }
141+
142+ // Set a timeout to check position after scroll momentum stops
143+ bounceCheckTimeout = setTimeout(() => {
144+ const finalScrollPos = Math.max(0, window.pageYOffset || document.documentElement.scrollTop);
145+ if (finalScrollPos <= 50 && !isVisible) {
146+ navbar.style.transform = "translateY(0)";
147+ isVisible = true;
148+ prevScrollPos = finalScrollPos;
149+ }
150+ }, 150);
151+ }, { passive: true });
152+
153+ // Handle page visibility changes (when switching tabs/apps)
154+ document.addEventListener("visibilitychange", function() {
155+ if (!document.hidden) {
156+ const currentScrollPos = Math.max(0, window.pageYOffset || document.documentElement.scrollTop);
157+ if (currentScrollPos <= 50) {
158+ navbar.style.transform = "translateY(0)";
159+ isVisible = true;
160+ prevScrollPos = currentScrollPos;
161+ }
72162 }
73163 });
74164});
0 commit comments