Hide on Scroll Navbar — Free HTML CSS JS Auto-Hiding Navigation Snippet

Hide on Scroll Navbar · Navigation · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Single transform-only CSS class change drives the entire hide/show animation for smooth performance
requestAnimationFrame throttling caps the scroll handler to once per rendered frame
Minimum scroll delta threshold prevents flicker from tiny trackpad/momentum scroll events
Navbar is always forced visible near the top of the page regardless of scroll direction
Reappears immediately on any upward scroll — no delay, matching user intent instantly
Fixed positioning keeps the navbar correctly placed regardless of page scroll position
Works with any navbar content — links, logo, CTA button — with no changes to the scroll logic
No external scroll or animation library — plain window scroll events and CSS transitions
Lightweight: one scroll listener, one boolean flag, one CSS class toggle
No framework, no build step required

About this UI Snippet

Hide on Scroll Navbar — HTML, CSS & JavaScript Auto-Hiding Nav

Screenshot of the Hide on Scroll Navbar snippet rendered live

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:

text
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

  1. 1
    Load the snippetClick "Hide on Scroll Navbar" in the sidebar Library tab. The preview shows a fixed navbar above a tall scrollable page.
  2. 2
    Scroll downScroll down through the page content in the preview and watch the navbar smoothly slide up out of view.
  3. 3
    Scroll up even slightlyScroll back up even a small amount and the navbar reappears immediately, sliding back down into place.
  4. 4
    Adjust 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.
  5. 5
    Adjust 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.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for React, or "Tailwind" for React + Tailwind CSS.

Real-world uses

Common Use Cases

Content-heavy mobile sites
Reclaim vertical viewport space while a user is reading or scrolling through content, without permanently removing navigation access.
Learn scroll-direction detection and throttling
Study how comparing consecutive scroll positions plus requestAnimationFrame throttling produces a smooth, performant scroll-linked effect.
Prototype a mobile-first product site
Drop this into a marketing site or blog prototype where maximizing visible content on scroll matters more than a permanently pinned navbar.
Match your existing navbar design
Keep your current navbar markup and styling — this pattern only needs the hide/show class and scroll logic layered on top of any navbar.
Keep navigation reachable at all times
Because the navbar reappears on any upward scroll, users are never more than a small scroll gesture away from full navigation access.
Combine with a scroll-progress or shrinking navbar
Layer this hide/show logic alongside a scroll-percentage progress bar or a navbar that shrinks in height past a certain scroll depth.

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.