25 CSS Sticky Navigations

7 Pure CSS18 Light JSPublished

25 CSS sticky navigations for marketing headers, SaaS app shells, docs sites, and one-page scroll layouts — spanning shrink-on-scroll bars, hide/reveal headers, transparent-to-solid heroes, glass pill navbars, mega menus, scrollspy and reading-progress indicators, and mobile bottom tabs. Scoped under .sn-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.

Related15 CSS Navigation Menus28 CSS Hamburger Menus16 CSS Mobile Navigation Patterns32 CSS Tabs20 Tailwind CSS Sidebars

Premium template pickPartner: Cruip

Affiliate link

Building the whole landing page, not just this section?

You just browsed 25 sticky navs. Cruip makes complete Tailwind CSS templates for landing pages, SaaS websites and admin dashboards, coded in HTML, React, Next.js and Vue and used by 60K+ developers. Single templates start at $49.

Browse Cruip templates

Cruip. We may earn a commission, at no extra cost to you.

01. Pure CSS Sticky Navbar (No JavaScript, position:sticky) (opens in a new tab)

Published

Pure CSS
The baseline sticky header every other pattern in this collection extends. Two declarations pin a marketing or blog header to the top of its scroll container, and the rest of the demo is the part tutorials skip: why the header stops sticking when a parent has overflow:hidden, and how to stop in-page anchor links from landing underneath the bar.

03. Responsive Sticky Navbar with Hamburger Menu Toggle (opens in a new tab)

Published

Light JS
The mobile header that ships on most marketing sites, built the way an accessibility audit expects it: a real button that reports its state, a drawer that traps nothing but is properly hidden from assistive tech when closed, Escape and outside-click dismissal, and focus that returns to the toggle. The hamburger-to-close morph is pure CSS transforms.

05. Floating Glass Pill Sticky Navbar (Rounded, Backdrop Blur, Elevation) (opens in a new tab)

Published

Pure CSS
The detached pill header used across modern product and portfolio sites: lifted away from the viewport edge, rounded to a full radius, and frosted so the page reads through it as it scrolls past. The demo covers the two things that make or break the effect — a genuinely layered rim light instead of a flat border, and a solid fallback where backdrop blur is unavailable.

06. Sticky Header Shrink on Scroll (80px → 50px, Compact State) (opens in a new tab)

Published

Light JS
The tall-at-rest header that compacts into a slim bar once the reader is past the first screen — buying back vertical space on long pages without ever losing the navigation. Driven by a scroll-progress timeline in CSS, so the shrink interpolates smoothly with the scroll position instead of snapping at a threshold, with a small script covering engines that have not shipped the timeline yet.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

07. Sticky Nav with Directional Hide (Scroll Down) and Reveal (Scroll Up) (opens in a new tab)

Published

Light JS
Reading-first navigation: the header slides out of the way while the reader moves down the page and snaps back the instant they scroll up, so the nav is always one small gesture away without permanently costing 64px of screen. The demo focuses on the two details that separate a polished implementation from a twitchy one — a movement dead zone and a rest state at the very top.

08. Transparent-to-Solid Sticky Header on Hero Scroll (opens in a new tab)

Published

Light JS
The hero pattern used on almost every launch page: the header sits transparently over full-bleed imagery, then takes on a solid, legible background the moment it starts overlapping real content. Implemented with the scroll-state container query — CSS can now style a stuck element without a single scroll listener — plus a sentinel-based fallback for engines that have not shipped it.

Published

Light JS
The indicator that glides between links instead of fading in place — the detail that makes a header feel engineered rather than assembled. One shared underline element is translated and resized to whatever link is hovered, focused or current, so the motion always reads as a single object moving, not four separate underlines taking turns.

12. Sticky Header with Theme-Aware Token Swap (Light/Dark) (opens in a new tab)

Published

Light JS
Theming a sticky header is harder than theming a page, because translucent chrome has to stay legible over whatever scrolls beneath it in both schemes. This demo wires the modern token cascade — system preference as the default, an explicit override on top — using the light-dark() function, so a single token definition serves both themes instead of two duplicated blocks.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

15. Neumorphic Sticky Navigation Bar (Soft-UI Inset/Outset Shadows) (opens in a new tab)

Published

Pure CSS
Soft-UI applied to a sticky bar, with the physics done properly: every raised surface casts one light and one dark shadow from a single consistent light source, and active items invert to inset so they read as genuinely pressed into the panel. Includes the guardrails that keep the style usable — because the classic failure of this aesthetic is unreadable, un-focusable controls.

16. Sticky Header with Multi-Column Mega Menu Dropdown (opens in a new tab)

Published

Light JS
Category navigation for a catalogue that does not fit in a list: a full-width panel with grouped columns and a promoted product, opening from a sticky header so it stays reachable at any scroll depth. Built as a disclosure rather than a menu, which is what lets it work identically for pointer, keyboard and touch.

22. Mobile Bottom Tab Bar with Safe-Area Inset Padding (opens in a new tab)

Published

Light JS
The thumb-zone navigation that mobile web apps and PWAs are judged on: five destinations pinned to the bottom of the scroll port, spaced above the home indicator instead of underneath it, with hit targets that survive a moving bus. Toggle the simulated inset in the demo to see exactly what breaks on a notched device.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

24. Sticky Horizontal Scroll Tab Bar with Snap Points (opens in a new tab)

Published

Light JS
Category rails carry the whole navigation of a menu, a storefront or a news app on a phone: more tabs than fit, pinned to the top of the view, snapping cleanly as a thumb flicks across them. This build pairs the scroll mechanics with the full keyboard tab pattern, so the rail works identically from a trackpad, a thumb and an arrow key.

25. Sticky Header with Social Share Icons for Articles (opens in a new tab)

Published

Light JS
Publishers put share actions in the sticky chrome because the moment a reader decides to pass an article on is unpredictable. This build keeps a share cluster in the header, adds a vertical rail that appears once the hero is behind the reader, folds to a thumb-reachable bar on phones, and does it without loading a single third-party widget.
FAQ

Frequently asked questions

What is CSS position: sticky and how is it different from position: fixed?
position: sticky is a hybrid: an element behaves as position: relative until its containing block scrolls past a threshold you set (typically top: 0), then it flips to position: fixed and pins to that edge — but ONLY within the bounds of its scroll container / containing block. When the container's bottom scrolls past, the sticky element scrolls away with it. position: fixed, in contrast, pins to the viewport permanently regardless of scroll position or containing block. That difference matters for real product work: a sticky header inside a scrollable article panel stops sticking when the article ends (correct — the header belongs to that panel), while a fixed header overlays every scroll surface on the page (often wrong — it fights modal overlays, embedded scrollers, and any nested scroll container). Sticky also has no layout side-effects when NOT stuck: the reserved space is honored, so content doesn't jump when the flip happens. Every demo in this collection uses position: sticky as the base primitive; fixed is only used for the mobile bottom tab bar (Demo 22) where viewport-pinning IS the intent.
Why does my sticky header sometimes not stick? The overflow:hidden parent gotcha.
This is the #1 sticky-navigation bug. If ANY ancestor between your sticky element and the scroll root has overflow: hidden, overflow: auto, or overflow: scroll, that ancestor becomes the sticky element's scroll container — and the sticky no longer sticks against the viewport. It sticks against that shorter ancestor, which usually means it doesn't visibly stick at all. Common triggers: a card wrapper with overflow: hidden to clip rounded corners, a modal body with overflow-y: auto, a Tailwind class like overflow-clip anywhere in the chain. Fix: remove the overflow rule from the ancestor (usually the fastest fix), OR move the sticky element outside the constrained ancestor, OR change the ancestor's overflow to overflow: visible. Debug: in DevTools, right-click the sticky element → Inspect → search up the ancestor chain for overflow:. Every ancestor is a suspect until proven visible. Every demo in this collection ships with the sticky element as a direct child of body or a scroll-clean container so the bug can't reproduce.
How do I hide a sticky header on scroll-down and reveal it on scroll-up?
The user-friendly "smart" header pattern. Demo 07 is the reference. The core logic: track the previous scroll position in a variable, compare to current on every scroll event, if current > previous → scrolling down → add a hidden class that translates the header up out of view, if current < previous → scrolling up → remove the class. Two production refinements: (1) add a minimum scroll threshold (e.g. if (current < 100) return) so the header always shows in the first viewport, and (2) throttle with requestAnimationFrame so the listener never runs more than once per frame. The CSS side is one transform: translateY(-100%); transition: transform 200ms ease-out — no display: none, no height: 0, because those cause layout jank and destroy focus. Modern browsers also support scroll-timeline as a JS-free alternative, but Safari lags on that as of 2026 — the JS approach is universal today.
How do I build a mobile bottom tab bar that respects the iPhone home indicator?
The iOS "safe area" gotcha. iPhone X and later have a home indicator strip at the bottom of the screen; content painted underneath it is invisible / untappable. CSS solves this with the env(safe-area-inset-bottom) function, which returns the OS-reported inset (34px on newer iPhones, 0 on Android and older devices). Demo 22 is the reference — its bottom tab bar uses padding-block-end: env(safe-area-inset-bottom, 0px) so the tabs sit ABOVE the home indicator, not under it. Two setup steps you can't skip: (1) add <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> to your HTML — WITHOUT viewport-fit=cover, iOS shrinks your layout to avoid the safe area and env() returns 0, so the padding does nothing. (2) Provide the fallback 0px in env(safe-area-inset-bottom, 0px) so browsers that don't support env() (very rare in 2026 — only pre-2020 Firefox / Edge) don't fall back to auto, which is invalid on padding. Android + desktop see zero extra padding; iOS with home indicator gets the correct offset. Zero conditional CSS, zero user-agent sniffing.
How do I add an active-section scrollspy to a sticky navbar?
Scrollspy is the pattern where sticky-nav links auto-highlight as their target sections scroll into view — Demo 23 is the reference. The old jQuery approach used a scroll listener that measured every section's bounding rect on every event: correct, but wasteful. Modern approach: IntersectionObserver with rootMargin tuned to the sticky header's height. Set up one observer with threshold: 0 and rootMargin: '-80px 0px -60% 0px' (top negative offset = sticky header height; bottom -60% = only mark active when the section is in the top 40% of the viewport). Point it at every section. In the callback, on isIntersecting switch, update the nav link's aria-current="true" attribute and let CSS style off that — a[aria-current="true"] { color: var(--accent); border-bottom-color: currentColor }. Never classList.add('active'): aria-current is semantically correct, screen-reader-announced, and doubles as the style hook. Bonus: on nav-link click, smooth-scroll to the target with scrollIntoView({ behavior: 'smooth', block: 'start' }) guarded behind prefers-reduced-motion. The full pattern is 22 lines of JS.
What's the accessible pattern for a sticky mega menu dropdown?
Mega menus (Demo 16) are the highest-risk accessibility surface in a sticky navbar — they layer complex interactive content on top of the page and must remain keyboard, screen-reader, and focus-trap-safe. The reference recipe: (1) The top-level trigger is a real <button type="button"> with aria-expanded="false" and aria-controls="mega-panel-id". (2) The mega panel has role="region" + aria-labelledby pointing at the trigger's ID. (3) On open (click OR keydown Enter/Space), flip aria-expanded to true, remove hidden from the panel, move focus to the FIRST link inside the panel — NOT to the panel itself. (4) Escape key closes the panel AND returns focus to the trigger. (5) Click-outside detection via a bubbling document.click listener that checks !panel.contains(e.target) && e.target !== trigger. (6) Tab from the last link inside the panel closes the panel and moves focus to the next nav element after the trigger. Skip focus trap for mega menus — traps belong to modals; menus should be exit-easy via Escape or Tab. Every interactive element inside the panel needs a visible focus ring (:focus-visible). Grid layout inside the panel needs proper heading structure (<h3> per column) so screen readers can navigate by heading.
How do sticky navigation patterns port to React, Vue, Svelte, Next.js, Tailwind?
The CSS ports unchanged — every .sn-NN selector, every keyframe, every custom property is framework-agnostic. What changes is where the JS lives. React: wrap the scroll listener in useEffect(() => { const cleanup = init(ref.current); return cleanup }, []) so it registers on mount and removes on unmount — never re-register on every render. Vue 3: onMounted(() => init(ref.value)) + onBeforeUnmount for cleanup. Svelte: onMount(() => { init(el); return cleanup }). Next.js App Router: mark the sticky-nav component with 'use client' — sticky positioning is a browser primitive, no SSR value. Tailwind: the class attribute on each demo can be mechanically translated (sticky → sticky, top: 0 → top-0, z-index: 40 → z-40, backdrop-blur → backdrop-blur-md); custom-property tokens become CSS vars in your @theme block. Bootstrap 5: the built-in .sticky-top class covers the base case; layer these demos' custom behaviours on top. Every demo's JS is written as a plain init function (usually 15-40 lines) — strip the IIFE wrapper and call from your framework's lifecycle hook. Zero framework lock-in.

Related collections

32 CSS Accordions — Vertical & Horizontal preview

32 CSS Accordions — Vertical & Horizontal

32 free CSS accordions covering pure-CSS FAQ blocks with details/summary, mobile navigation menus, e-commerce filter sidebars, nested tree views, exclusive single-open groups and smoothly animated height:auto — plus 26 visual variations in vertical, horizontal and hybrid layouts. Copy-paste HTML and CSS, no JavaScript.

39 CSS Breadcrumbs preview

39 CSS Breadcrumbs

39 hand-coded CSS breadcrumbs — Schema.org BreadcrumbList Microdata + WCAG 2.2 accessible (Google Rich Results eligible), :has() responsive collapse, dark/light theme toggle with color-mix, Shopify/Amazon e-commerce filter chip removal, Vercel/Linear/Notion SaaS dashboard app-shell pattern, Docusaurus/Mintlify sticky scroll-shrink header, Amazon-style dropdown sibling menus, NFT/Web3 holographic shimmer (@property + conic-gradient), SaaS marketing gradient text, Airbnb filter chip with container queries, editorial blog wave underline, developer docs one-click path copy (Clipboard API), and 26 more. Semantic HTML: <nav aria-label='Breadcrumb'> + <ol> + aria-current='page'. Framework-agnostic, MIT-licensed.

26 CSS Circular Menus preview

26 CSS Circular Menus

26 hand-coded CSS circular and radial menu designs, from the floating-action FAB speed dial and dashboard radial hubs to game-style pie-slice wheels, SVG gooey metaball fans, hexagonal honeycombs, iris-aperture reveals, orbiting satellites on offset-path, compass-rose directional nav, sci-fi HUD rings, glassmorphism popovers built on the native Popover API, vinyl-record players, and full-takeover nebula overlays on native dialog. Every design uses CSS trigonometry (sin(), cos()) or the counter-rotation trick for positioning, ships real keyboard navigation, aria-labels on icon-only buttons, and a prefers-reduced-motion guard. Copy-paste HTML, CSS and vanilla JS with zero framework dependencies — MIT licensed.

Search CodeFronts

Loading…