Nav Bars
Shrink-on-scroll nav
Tall header that compacts once the page moves
Tall header that compacts once the page moves
Create a header with Tailwind CSS that starts tall and compacts on scroll. At rest the bar is roughly 88 pixels tall with a transparent background, a large wordmark, spaced-out links in slightly larger text and an outline call-to-action. Once the page has scrolled past 40 pixels it becomes 60 pixels tall with a white background, a hairline bottom border, a soft shadow, a smaller wordmark and a filled dark button, all handled by class toggles on a single container with transition utilities on height, padding, background and shadow. Add a thin reading-progress line pinned to the bottom edge of the header, filling in neutral-900 as the page scrolls. Include a page of placeholder blocks below so the behaviour is visible. Then add JavaScript that toggles the compact classes past the threshold using a passive scroll listener, and updates the progress line width from the scroll ratio. <header id="shrinkNav" class="fixed inset-x-0 top-0 z-40 transition-all duration-300">
<div id="shrinkInner" class="mx-auto flex h-22 max-w-6xl items-center justify-between px-6 transition-all duration-300" style="height:88px">
<a href="#" id="shrinkMark" class="text-2xl font-semibold tracking-tight text-neutral-900 transition-all duration-300">Fernbrook</a>
<nav class="hidden items-center gap-8 text-sm text-neutral-600 md:flex">
<a href="#" class="transition hover:text-neutral-900">Work</a>
<a href="#" class="transition hover:text-neutral-900">Studio</a>
<a href="#" class="transition hover:text-neutral-900">Journal</a>
<a href="#" class="transition hover:text-neutral-900">Contact</a>
</nav>
<a href="#" id="shrinkCta" class="rounded-xl border border-neutral-300 px-4 py-2 text-sm font-medium text-neutral-900 transition-all duration-300">Start a project</a>
</div>
<div class="h-0.5 w-full bg-transparent">
<div id="shrinkProgress" class="h-full w-0 bg-neutral-900 transition-[width] duration-150"></div>
</div>
</header>
<main class="mx-auto max-w-3xl space-y-6 px-6 pb-24 pt-36">
<h1 class="text-4xl font-semibold tracking-tight text-neutral-900">A studio for careful software</h1>
<p class="text-lg leading-relaxed text-neutral-500">Scroll and the header settles into its compact state, keeping the wordmark and the call to action reachable without taking a third of the screen.</p>
<div class="h-64 rounded-2xl bg-neutral-100"></div>
<div class="h-64 rounded-2xl bg-neutral-100"></div>
<div class="h-64 rounded-2xl bg-neutral-100"></div>
<div class="h-64 rounded-2xl bg-neutral-100"></div>
</main> var nav = document.getElementById("shrinkNav");
var inner = document.getElementById("shrinkInner");
var mark = document.getElementById("shrinkMark");
var cta = document.getElementById("shrinkCta");
var progress = document.getElementById("shrinkProgress");
var compact = false;
function apply(state) {
if (state === compact) return;
compact = state;
nav.classList.toggle("bg-white", state);
nav.classList.toggle("shadow-sm", state);
nav.classList.toggle("border-b", state);
nav.classList.toggle("border-neutral-200", state);
inner.style.height = state ? "60px" : "88px";
mark.classList.toggle("text-2xl", !state);
mark.classList.toggle("text-lg", state);
cta.classList.toggle("bg-neutral-900", state);
cta.classList.toggle("text-white", state);
cta.classList.toggle("border-neutral-900", state);
cta.classList.toggle("text-neutral-900", !state);
cta.classList.toggle("border-neutral-300", !state);
}
function onScroll() {
apply(window.scrollY > 40);
var max = document.documentElement.scrollHeight - window.innerHeight;
var ratio = max > 0 ? window.scrollY / max : 0;
progress.style.width = (ratio * 100).toFixed(2) + "%";
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();