You Might Also Like
Hide on Scroll Navbar — Free HTML CSS JS Auto-Hiding Navigation Snippet
Hide on Scroll Navbar · Navigation · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Hide on Scroll Navbar — HTML, CSS & JavaScript Auto-Hiding Nav

A navbar that's always visible takes up permanent vertical space on every screen, which matters most on mobile where every pixel of viewport height counts. The common fix is a navbar that hides itself while a user is actively scrolling down to read content, and reappears the instant they scroll back up looking for navigation — a pattern used across countless content-heavy mobile sites and apps.
This snippet implements that exact behavior in plain HTML, CSS, and vanilla JavaScript.
How the hide/show animation works
The navbar is position: fixed at the top of the viewport. Hiding it is a single CSS class, .hidden, that applies transform: translateY(-100%) — moving the navbar up by exactly its own height, off the top of the screen. A transition: transform 0.25s ease on the base .navbar rule makes that hide/show animate smoothly rather than snapping instantly. Only one property ever changes, which keeps the animation cheap for the browser to run — transform-only animations can run on the compositor thread without triggering layout recalculation.
How scroll direction is detected
A single lastScrollY variable stores the scroll position from the previous check. On every scroll event, delta = currentY - lastScrollY tells you both the direction (positive means scrolling down, negative means scrolling up) and the magnitude of the most recent scroll movement.
Why a minimum delta threshold matters
Trackpads and some mice report many tiny scroll events per second, and reacting to every single one — even 1-2px movements — makes the navbar flicker distractingly. MIN_SCROLL_DELTA (8px here) ignores any scroll movement smaller than that threshold, and only actually evaluates direction once a scroll of meaningful size has accumulated.
Why requestAnimationFrame wraps the handler
The native scroll event can fire dozens of times per second. Wrapping the actual direction-check logic in requestAnimationFrame, guarded by a ticking boolean, ensures the check runs at most once per rendered frame rather than once per raw scroll event — a standard throttling technique that keeps scroll-linked JavaScript from becoming a performance bottleneck.
The reveal threshold near the top
Below REVEAL_THRESHOLD (80px), the navbar is always forced visible regardless of direction — this avoids the slightly odd feeling of the navbar hiding itself while the user is still very close to the top of the page, where it should always be reliably present.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Give this snippet's HTML, CSS, and JS to an AI coding assistant like Claude and ask it to explain why wrapping the scroll handler in requestAnimationFrame with a ticking guard is more effective throttling than a plain setTimeout-based debounce for this specific use case, and why using only a CSS transform (rather than animating top or margin-top) keeps the hide/show animation running smoothly even on lower-powered devices. It's also worth asking the assistant to help you handle the accessibility gap where a visually hidden, translated-off-screen navbar can still receive keyboard focus — specifically how to toggle tabindex or aria-hidden on its interactive children in sync with the hidden class without breaking the existing scroll logic.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a sticky navbar that hides when scrolling down and reappears immediately when scrolling up, in plain HTML, CSS, and JavaScript — no scroll library.
Requirements:
- A fixed-position navbar at the top of the viewport that hides via a single CSS class using only a transform: translateY property (not top, margin, or height) so the hide/show animation is compositor-friendly, with a CSS transition providing the smooth slide.
- Track scroll direction in JavaScript by comparing the current window.scrollY against the value from the previous check, stored in a variable between scroll events.
- Wrap the actual direction-check logic in requestAnimationFrame, guarded by a boolean flag, so it runs at most once per rendered frame rather than on every raw scroll event.
- Ignore scroll movements smaller than a configurable minimum delta (a named constant) to prevent the navbar from flickering in response to tiny scroll jitter from trackpads or momentum scrolling.
- Force the navbar to always remain visible whenever the scroll position is below a second configurable threshold near the top of the page, regardless of the detected scroll direction.
- The navbar's contents (logo, links, a call-to-action button) should be ordinary markup with no special requirements imposed by the hide/show logic, so any existing navbar could adopt this behavior by adding the class-toggling script.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Load the snippetClick "Hide on Scroll Navbar" in the sidebar Library tab. The preview shows a fixed navbar above a tall scrollable page.
- 2Scroll downScroll down through the page content in the preview and watch the navbar smoothly slide up out of view.
- 3Scroll up even slightlyScroll back up even a small amount and the navbar reappears immediately, sliding back down into place.
- 4Adjust the sensitivityIn the JS panel, change MIN_SCROLL_DELTA to make the navbar more (lower value) or less (higher value) sensitive to small scroll movements.
- 5Adjust the top reveal zoneIn the JS panel, change REVEAL_THRESHOLD to control how close to the top of the page the navbar is always forced visible.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for React, or "Tailwind" for React + Tailwind CSS.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The script stores the scroll position from the previous check in a lastScrollY variable and compares it to the current scrollY on each scroll event. A positive difference means the page has scrolled down since the last check; a negative difference means it scrolled up.
A MIN_SCROLL_DELTA threshold (8px by default) ignores scroll changes smaller than that amount. This prevents the navbar from flickering rapidly in response to the many tiny scroll events some trackpads and mice generate during smooth or momentum scrolling.
The scroll event can fire far more often than the screen actually repaints. Wrapping the direction-check logic in requestAnimationFrame, guarded by a ticking flag, ensures it runs at most once per rendered frame, keeping the scroll handler cheap and avoiding jank on long pages.
The REVEAL_THRESHOLD constant (80px by default) forces the navbar visible whenever the scroll position is below that value, regardless of direction — this avoids the odd feeling of the navbar hiding itself while the user is still essentially at the top of the page.
It only moves it visually, using transform: translateY(-100%). The element remains in the DOM and in the accessibility tree; if you need it to also be unreachable by keyboard when hidden, add aria-hidden="true" and toggle tabindex="-1" on its links alongside the hidden class.
Yes. Instead of translateY(-100%), define a "compact" class that reduces the navbar's height and font sizes, and toggle that class using the same scroll-direction logic instead of (or in addition to) the hide/show transform.
It can interact with them if those features also read or set scroll position rapidly. Test the combination carefully — you may need to adjust MIN_SCROLL_DELTA or temporarily disable the hide behavior during a programmatic smooth-scroll triggered by an anchor link.
The navbar remains fully focusable at all times since only its visual transform changes, not its DOM presence — but a hidden, off-screen navbar can still receive focus, which may be confusing. For full accessibility, also toggle tabindex or aria-hidden on the navbar's interactive children when it is hidden.