Glassmorphism✨ Premium

Frosted Glass Navbar

A frosted navigation bar stuck to the top of a scrolling area: at rest, a 12 px blur and an 8% white veil; from 10 px of scrolling, the glass thickens — 24 px blur, saturation ×2, 15% veil — in 0.4 s, so the text passing underneath no longer gets in the way of the links.

Backdrop-filterScrollFrosted

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Glassmorphism has 47 effects, including 6 free. Explore the category →

3 usage examples

A jazz festival's menu above a photo-led line-up — Frosted Glass Navbar example 1

① A jazz festival's menu above a photo-led line-up

WhenThe festival-goer browses tonight's concerts: the quartet's full-frame photo at the top, then the four stages' times, while the navigation bar stays at the top.
WhyAs long as the stage photo is alone under the bar, the glass stays light and lets the light beams through; as soon as the timetable rises, it thickens and the heading “Tonight in the orchard” only passes under the links as a blurred smudge. The bar keeps its place at the top of the area for the whole way down.
SettingsArea enlarged to 540 × 360 px, square corners; 46 px bar (margin-bottom: -46px to stay over the content), 15 px brand, 12 px links in pills, the “Line-up” entry marked active in the style of Glass Navigation (fx-0303); no top padding on the content so the photo starts under the glass. Automatic scrolling for the capture, 140 px/s.
Navigation of a cycling travel journal — a blog of full-frame photos — Frosted Glass Navbar example 2

② Navigation of a cycling travel journal — a blog of full-frame photos

WhenThe reader scrolls down the story of a stage along the Loire: a photo of the road at the top, then the paragraphs, then another photo.
WhyThe blog lives on its photos, which must reach the top of the screen, and on its text, which must stay readable under the menu. The thickening settles the conflict without permanently choosing one or the other: the sky and the poplars show through the bar at rest, the lines of the story pass under it blurred while reading.
SettingsSame 46 px bar; 14 px serif story text on a cream background. Light page: in the thickened state, the veil is tinted dark (.scrolled { background: rgba(43,42,38,.55) }) — with the original white veil, the white links got lost on the cream.
Header of a step-by-step recipe — an online food magazine — Frosted Glass Navbar example 3

③ Header of a step-by-step recipe — an online food magazine

WhenThe cook scrolls through the steps of a beef and carrot stew, pot seen from above at the top: the bar keeps the ingredients and the timer within reach.
WhyAt rest you see the pot and the tablecloth through the bar; while reading it becomes more opaque and the links stay readable even when a step heading passes underneath. The timer stays within a finger's reach, hands covered in flour, without scrolling back up.
Settings46 px bar, “Steps” entry active; a 260 px photo at the top, then numbered steps in white on a dark brown #1f1a17 background, so the code's white veil stays readable.

How it works

A 280 × 180 px .lg-navbar-scene area (12 px corners, indigo gradient at 160°) that the script switches to overflow: auto, a 38 px .lg-frosted-nav bar at the top, and the content below. The bar is a pane of glass: backdrop-filter: blur(12px) saturate(1.6) (with its -webkit- form), 8% white fill, 12% white rule at the bottom. It is position: sticky; top: 0 with margin-bottom: -38px: it stays at the top of the area throughout the scroll, and the negative margin makes it sit over the content instead of pushing it down — so the text slides under the glass. The content keeps a 50 px top padding so it does not start hidden.

The script (7 lines, no dependency) walks every [data-navbar-scene] on the page, listens to its scrolling and adds the .scrolled class to the bar as soon as scrollTop exceeds 10 px, removing it below. .scrolled doubles the blur (24 px), pushes saturation to 2, raises the veil to 15% and the rule to 20%; the 0.4 s transition covers backdrop-filter and background. Measured 150 ms after crossing the threshold: 19.4 px blur and 1.85 saturation in Chromium 151 and Firefox 153, 19.1 px in WebKit 26.5 — all three interpolate the blur; at 600 ms, 24 px everywhere; back at 5 px of scrolling, the class drops. The script also adds 120 px of bottom padding to the content, which gives the demo 90 px of travel.

Why position: sticky with a negative margin rather than position: absolute: inside a scrolling area, an absolutely positioned element is placed relative to the area's content and scrolls with it. Measured in a blank page, an absolute bar would move up 60 px at 60 px of scrolling, out of the area, and 90 px at the end of the travel — the thickened glass would only show between 10 and 38 px, then the bar would vanish with its links. Sticky, it stays at 0 px from the top at 0, 60 and 90 px of scrolling, in Chromium, Firefox and WebKit; the −38 px margin makes it float over the content instead of pushing it down.

Accessibility

  • Links: the three “Home / About / Contact” entries are spans (cursor: default): measured, none receives keyboard focus and a screen reader does not announce them as links. On your site, replace them with <a href> inside a <nav aria-label="Main">, add a :focus-visible style (2 px white outline) and mark the current page with aria-current="page".
  • Text size and contrast: the links are 8.8 px (.55rem) and the brand 11.2 px — too small for navigation; raise them to 12-14 px. Links in 80% white: 6.5:1 at rest over the #312e81 violet, 5.4:1 once the bar thickens, but 4.1:1 then 3.6:1 over the #4f46e5 part of the gradient. The whiter veil slightly lowers contrast over a flat background; what it gains is that the text scrolling underneath becomes a blurred smudge instead of letters overlapping the links.
  • Motion: the 0.4 s transition only fires on scroll, at the reader's request. The “Scroll me” hint, however, blinks forever (opacity 0.4 ↔ 0.9 every 2 s): add @media (prefers-reduced-motion: reduce) { .lg-navbar-scroll-hint { animation: none } }, or remove it. Its 8 px text in 40% white is also unreadable: 2.3:1 at best over the bottom of the gradient, 1.6:1 over its lightest part (#818cf8).
  • Scrolling area: in the demo, the 180 px area scrolls, not the page. Firefox and Safari only give it keyboard focus with tabindex="0"; on your site, rather apply the effect to the whole page's scrolling (see the FAQ), which the keyboard already knows how to scroll.
  • Reduced transparency: nothing is provided for prefers-reduced-transparency; a solid fill there would keep the links readable whatever the content underneath: .lg-frosted-nav, .lg-frosted-nav.scrolled { background: #1e1b4b; backdrop-filter: none }.

Browser compatibility

CSS: backdrop-filter (and -webkit-backdrop-filter), a transition on backdrop-filter, position: sticky, linear gradient, opacity animation. JS: querySelectorAll, addEventListener('scroll'), classList. Zero dependencies. Measured in Chromium 151, Firefox 153 and WebKit 26.5: bar stuck to the top from start to end, .scrolled class set past 10 px and removed below, blur interpolated from 12 to 24 px in all three, no console error.

Chrome 76+✓ Full
Firefox 103+✓ Full
Safari 9+✓ Full (-webkit- prefix before version 18, included in the code)
Edge 79+✓ Full
Mobile iOS 13+✓ Full (the finger scrolls the area)
Android Chrome 76+✓ Full

Without backdrop-filter (Firefox before 103, Chrome before 76), the bar remains an 8% then 15% white veil with no blur: the thickening still shows, but the text passing underneath stays sharp. For those browsers, give .scrolled a more opaque fill inside @supports not (backdrop-filter: blur(1px)). position: sticky has existed since 2017 (Chrome 56, Firefox 59, Safari 13).

The code

HTML structure to paste into your page (the CSS + JS come with Premium):

index.html — structure
<div class="demo-preview">
  <div class="lg-navbar-scene" data-navbar-scene="">
    <div class="lg-frosted-nav">
      <span class="lg-nav-brand">…</span>
      <div class="lg-nav-items">
        <span>…</span>
        <span>…</span>
        <span>…</span>
      </div>
    </div>
    <div class="lg-navbar-content">…</div>
    <div class="lg-navbar-scroll-hint">…</div>
  </div>
</div>
Unlock the full code — $9.90/mo incl. tax

The full HTML + CSS + JS of Frosted Glass Navbar, ready to paste — plus all 840 effects. Or $299 once, lifetime access.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Trigger threshold (JS — e.scrollTop > 10) 10 px Higher (for instance the height of your header photo, 250 px), the bar stays light while the photo is under it and only thickens when the text arrives. 0 makes it react at the first pixel.
Glass at rest and thickened (CSS — .lg-frosted-nav and .lg-frosted-nav.scrolled) rest: 12 px blur, saturate 1.6, 8% white; thickened: 24 px blur, saturate 2, 15% white Change backdrop-filter and -webkit-backdrop-filter together. On a light page, tint the thickened state dark (background: rgba(43,42,38,.55)) or switch the links to a dark color. A bigger gap between the two states (8 px → 30 px) makes the change more visible.
Transition duration (CSS — transition: backdrop-filter .4s, background .4s) 0.4 s 0.2 s for an almost immediate change, 0.8 s for a slow thickening. Add border-bottom-color to the list so the rule follows at the same pace.
Bar height (CSS — height: 38px, margin-bottom: -38px) 38 px Always keep the bottom margin equal to minus the height: 46 px tall, margin-bottom: -46px. Otherwise the bar pushes the content down, and nothing passes under the glass at the start.
Links, hover and active page (CSS — .lg-nav-items span) 8.8 px, 80% white, pure white on hover To get the style of Glass Navigation (fx-0303): padding: 6px 12px; border-radius: 8px, hover background: rgba(255,255,255,.1), current page as a pill background: rgba(139,92,246,.3); border: 1px solid rgba(139,92,246,.4). Turn the spans into a elements for the keyboard.
“Scroll me” hint (HTML + CSS — .lg-navbar-scroll-hint) 8 px, 40% white, blinks every 2 s, scrolls with the content It only makes sense in the small demo area: delete the tag and the @keyframes lgScrollHintPulse on a real site.

FAQ

By wiring the same threshold to the window. Make the header position: sticky; top: 0 (or fixed) with a z-index above the content, keep both CSS states, and replace the script with: var n = document.querySelector('.lg-frosted-nav'); addEventListener('scroll', function () { n.classList.toggle('scrolled', scrollY > 10) }, { passive: true });. Remove data-navbar-scene and the area's inline overflow: auto, otherwise it would scroll on its own. Measured in Chromium and Firefox on a 3,000 px page: after 600 px of wheel, bar at 0 px from the top, .scrolled class set, blur at 24 px. For the content to pass under the bar from the top of the page, use a negative bottom margin (as here) or a fixed header with an opening photo that reaches the top.
Because a position: absolute bar inside the scrolling area would be placed relative to that area's content, not to its visible window: it would scroll with the text. Measured: at 60 px of scrolling, an absolute bar sits 60 px higher, out of the area — the thickened glass, the whole point of the effect, would only show between 10 and 38 px. position: sticky keeps it stuck to the top of the area, and the 38 px negative margin lets it float over the content. If you change the bar's height, change the margin with it.
Glass Navigation is the basic glass bar: a floating bar with 12 px rounded corners, set 20 px from the edges of a 360 × 200 px scene with two blurred orbs, a fixed 16 px blur, three real <button>s (reachable by keyboard) that take a 10% white fill on hover, and an active entry as a purple pill — but it reacts to nothing but hover, and its blur has no -webkit- form for Safari before 18. Frosted Glass Navbar makes the same glass bar, full width, and adds what matters on a real page: glass that thickens when content passes underneath. This page covers both: to get fx-0303's pills and hover, see “Links, hover and active page” in the table; the scenes on this page use them.