refactor: transition navigation to a persistent fixed-wrapper layout with improved scroll-based floating state styles

This commit is contained in:
Firman Ramdhani
2026-07-29 15:42:39 +07:00
parent 6506122033
commit b43df8f35b
2 changed files with 28 additions and 70 deletions
+8 -4
View File
@@ -61,10 +61,10 @@ export default function Page() {
return ( return (
<main> <main>
{/* ============ NAV + HERO ============ */} {/* ============ FIXED NAV ============ */}
<header className="hero"> <div className={`nav-wrapper ${isScrolled ? 'floating' : ''}`}>
<div className="container"> <div className="container">
<nav className={`nav ${isScrolled ? 'nav-floating' : ''}`}> <nav className="nav">
<div className="brand"> <div className="brand">
<a href="#"> <a href="#">
<div className="brand-mark"> <div className="brand-mark">
@@ -102,7 +102,11 @@ export default function Page() {
</div> </div>
</div> </div>
</nav> </nav>
<div className="nav-spacer"></div> </div>
</div>
<header className="hero">
<div className="container">
<div className="hero-inner"> <div className="hero-inner">
<h1> <h1>
+20 -66
View File
@@ -152,32 +152,7 @@
/* Animations that are hard to replicate purely via utility classes */ /* Animations that are hard to replicate purely via utility classes */
@layer utilities { @layer utilities {
.nav-floating {
position: fixed;
top: 16px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 40px);
max-width: 1120px;
background: var(--color-brand-1-900);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 24px 48px -20px rgba(0, 0, 0, 0.55);
z-index: 1000;
animation: navFloatIn 0.4s cubic-bezier(0.16, 0.8, 0.44, 1);
}
@keyframes navFloatIn {
from {
opacity: 0;
transform: translate(-50%, -16px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
.drift-a { .drift-a {
animation: driftA 7s ease-in-out infinite; animation: driftA 7s ease-in-out infinite;
@@ -392,59 +367,38 @@
} }
/* ---------- Nav ---------- */ /* ---------- Nav ---------- */
.nav-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
pointer-events: none; /* Let clicks pass through empty space */
}
.nav-wrapper .container {
pointer-events: auto; /* Enable clicks on the nav itself */
}
.nav { .nav {
position: relative;
z-index: 20;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 26px 0; padding: 26px 0;
transition: border-radius: var(--radius-md);
background 0.35s ease, margin-top: 0;
box-shadow 0.35s ease, border: 1px solid transparent;
padding 0.35s ease, transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
border-color 0.35s ease;
} }
.nav.nav-floating { .nav-wrapper.floating .nav {
position: fixed; margin-top: 16px;
top: 16px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 40px);
max-width: 1120px;
background: var(--color-brand-1-900); background: var(--color-brand-1-900);
backdrop-filter: blur(14px); backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--radius-md);
padding: 12px 26px; padding: 12px 26px;
box-shadow: 0 24px 48px -20px rgba(0, 0, 0, 0.55); box-shadow: 0 24px 48px -20px rgba(0, 0, 0, 0.55);
z-index: 1000;
animation: navFloatIn 0.4s cubic-bezier(0.16, 0.8, 0.44, 1);
}
@keyframes navFloatIn {
from {
opacity: 0;
transform: translate(-50%, -16px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
.nav-spacer {
display: none;
height: 0;
}
.nav-floating ~ .nav-spacer,
body.nav-is-floating .nav-spacer {
display: block;
height: 74px;
} }
.brand { .brand {
@@ -525,7 +479,7 @@ body.nav-is-floating .nav-spacer {
.hero-inner { .hero-inner {
position: relative; position: relative;
z-index: 2; z-index: 2;
padding: 8px 0 64px; padding: 94px 0 64px;
} }
.hero h1 { .hero h1 {