28 Tailwind Hamburger Menus
07 / 28

All 28 in 28 Tailwind Hamburger Menus

  1. 01Tailwind Hamburger Menu with Clip-Path Circle Expansion
  2. 02Tailwind Keyboard Navigable Hamburger Menu with ARIA Attributes
  3. 03Tailwind Animated 3-Line to X Hamburger Icon Toggle
  4. 04Tailwind Slide-In Off-Canvas Drawer with Dimmed Backdrop Overlay
  5. 05Pure Tailwind Checkbox Hack Hamburger Navigation (No JavaScript)
  6. 06Tailwind Responsive Hamburger Menu with Integrated Search Bar & Social Links
  7. 07Tailwind Glassmorphism Backdrop Blur Hamburger Navigation
  8. 08Tailwind Push Page Navigation Menu (Off-Canvas Content Shift)
  9. 09Pure Tailwind Hamburger Menu Without JavaScript
  10. 10Tailwind Hamburger Menu Morphing to Close Icon Animation
  11. 11Tailwind Full Screen Mobile Navigation Overlay
  12. 12Tailwind Slide Out Sidebar Navigation / Off Canvas Menu
  13. 13Tailwind Responsive Navbar Mobile Hamburger Toggle Breakpoints
  14. 14Tailwind Minimalist Floating Hamburger Button
  15. 15Tailwind CSS Responsive Hamburger Menu Component
  16. 16Tailwind Rebuild of the Bootstrap 5 Navbar Hamburger Toggle
  17. 17Tailwind WCAG Accessible Hamburger Menu Example
  18. 18Pure Tailwind Dropdown Slide Down Mobile Hamburger Menu
  19. 19Simple 3-Line Tailwind Hamburger Icon Hover Effect
  20. 20Tailwind Full Screen Blur Overlay Hamburger Menu
  21. 21Tailwind Mobile Bottom Navigation Bar with Floating Hamburger Toggle
  22. 22Pure Tailwind Multi-Level Accordion Hamburger Dropdown Menu
  23. 23Flexbox Navbar Right-Aligned Tailwind Hamburger Icon
  24. 24Radial Ripple Expand Tailwind Hamburger Menu
  25. 25Sticky Tailwind Navbar Shrinking Hamburger Icon on Scroll
  26. 26Neumorphic Tailwind Hamburger Toggle Button
  27. 27Brutalist Design Bordered Tailwind Hamburger Menu
  28. 28Tailwind 3D Flip Canvas Mobile Hamburger Navigation
Tailwind + JSMIT licensed

Tailwind Glassmorphism Backdrop Blur Hamburger Navigation

Real frosted glass, not grey-with-opacity — and Tailwind happens to have the exact utilities for it: backdrop-blur-[18px] backdrop-saturate-[1.7] compose into one backdrop-filter, no prefix juggling, no stacking order to remember. The stage runs drifting gradient blobs so you can see the glass working, and the mandatory @supports not fallback stays in CSS, where it belongs.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="thb-07 w-full min-h-svh grid justify-center content-start bg-thb07-bg font-thb07-sans text-thb07-ink px-5 py-9" aria-label="Glassmorphism backdrop blur menu demo">
  <div class="group relative isolate w-[min(400px,88vw)] h-135 rounded-3xl overflow-hidden bg-thb07-bg border border-thb07-edge">
    <i class="absolute z-0 -left-20 top-15 w-75 h-75 rounded-full blur-[70px] bg-thb07-blob1 animate-[thb07-drift_11s_ease-in-out_infinite_alternate] motion-reduce:animate-none" aria-hidden="true"></i>
    <i class="absolute z-0 -right-17.5 -bottom-10 w-65 h-65 rounded-full blur-[70px] bg-thb07-blob2 animate-[thb07-drift_13s_ease-in-out_infinite_alternate-reverse] motion-reduce:animate-none" aria-hidden="true"></i>
    <header class="relative z-3 flex items-center justify-between h-18 px-5.5">
      <span class="text-[17px] font-bold tracking-[0.22em] uppercase">lumen</span>
      <button type="button" aria-expanded="false" aria-controls="thb07-menu" aria-label="Open menu" class="grid place-items-center w-11.5 h-11.5 rounded-[14px] border border-[oklch(1_0_0/0.28)] bg-[oklch(0.97_0.01_260/0.1)] backdrop-blur-[12px] backdrop-saturate-[1.6] text-thb07-ink cursor-pointer transition-[background,scale] duration-250 hover:bg-[oklch(0.97_0.01_260/0.2)] hover:scale-105 active:scale-95 focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-3">
        <span class="relative block w-4.5 h-3" aria-hidden="true">
          <i class="absolute left-0 top-0 w-4.5 h-0.5 rounded-sm bg-current transition-[translate,rotate] duration-300 group-data-open:translate-y-[5px] group-data-open:rotate-45 motion-reduce:transition-none"></i>
          <i class="absolute left-0 top-[5px] w-4.5 h-0.5 rounded-sm bg-current transition-[opacity] duration-200 group-data-open:opacity-0 motion-reduce:transition-none"></i>
          <i class="absolute left-0 top-2.5 w-4.5 h-0.5 rounded-sm bg-current transition-[translate,rotate] duration-300 group-data-open:-translate-y-[5px] group-data-open:-rotate-45 motion-reduce:transition-none"></i>
        </span>
      </button>
    </header>
    <div class="relative z-1 grid justify-items-start gap-3.5 px-6.5 py-11.5" aria-hidden="true">
      <h2 class="text-[37px] leading-[1.05] font-bold tracking-[-0.03em] text-balance">Light, refracted.</h2>
      <p class="max-w-[26ch] text-sm leading-relaxed text-thb07-mut text-pretty">Studio for luminous interfaces &mdash; glass, gradients and grain.</p>
      <div class="mt-2.5 px-4 py-2.25 rounded-full border border-[oklch(1_0_0/0.25)] bg-[oklch(0.97_0.01_260/0.08)] backdrop-blur-[8px] text-[11.5px] font-semibold tracking-[0.12em] uppercase">Scroll &darr;</div>
    </div>
    <nav id="thb07-menu" aria-label="Site" class="thb07-glass absolute z-2 inset-x-4 top-21.5 bottom-4 flex flex-col justify-center gap-0.5 px-6.5 rounded-[20px] bg-[oklch(0.97_0.01_260/0.12)] backdrop-blur-[18px] backdrop-saturate-[1.7] border border-[oklch(1_0_0/0.28)] shadow-[inset_0_1px_0_oklch(1_0_0/0.25),0_24px_48px_-20px_oklch(0.2_0.05_280/0.5)] opacity-0 -translate-y-3.5 scale-[0.98] invisible [transition:opacity_.35s,translate_.4s_var(--ease-thb07),scale_.4s_var(--ease-thb07),visibility_0s_.4s] group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:scale-100 group-data-open:visible group-data-open:[transition:opacity_.35s,translate_.4s_var(--ease-thb07),scale_.4s_var(--ease-thb07),visibility_0s_0s]">
      <a href="#work" style="--i:0" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Work</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#services" style="--i:1" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Services</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#about" style="--i:2" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>About</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#contact" style="--i:3" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Contact</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <footer style="--i:4" class="flex items-center justify-between mt-5.5 text-xs text-thb07-mut opacity-0 translate-y-3 transition-[opacity,translate] duration-350 ease-thb07 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150">
        <span>&copy; 2026 lumen</span>
        <a href="#privacy" class="text-xs text-thb07-mut no-underline transition-[color] duration-200 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-2">Privacy</a>
      </footer>
    </nav>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-thb07-bg: #322a4d;
  --color-thb07-bg: oklch(0.22 0.045 285);
  --color-thb07-edge: #55496f;
  --color-thb07-edge: oklch(0.35 0.05 285);
  --color-thb07-ink: #f6f4fb;
  --color-thb07-ink: oklch(0.97 0.008 285);
  --color-thb07-mut: #c3bcd4;
  --color-thb07-mut: oklch(0.78 0.03 285);
  --color-thb07-acc: #6fd7e0;
  --color-thb07-acc: oklch(0.82 0.14 190);
  --color-thb07-blob1: #a03fd8;
  --color-thb07-blob1: oklch(0.62 0.23 310);
  --color-thb07-blob2: #4bc0d8;
  --color-thb07-blob2: oklch(0.75 0.16 200);
  --font-thb07-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb07-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-thb07: cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Keyframes are a rule, not a value — no utility form exists. */

@keyframes thb07-drift {
  from {
    translate: 0 0;
    scale: 1;
  }

  to {
    translate: 40px -30px;
    scale: 1.15;
  }
}
/* The one thing that MUST stay a feature query: without it, an engine with no
   backdrop-filter paints a 12%-alpha panel and page text crashes through the links. */

@supports not (backdrop-filter: blur(1px)) {
  .thb-07 .thb07-glass {
    background: oklch(0.25 0.04 280 / 0.94);
  }

  .thb-07 button[aria-controls="thb07-menu"] {
    background: oklch(0.3 0.05 280 / 0.85);
  }
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-07 {
  width: 100%;
  min-height: 100svh;
}
(function () {
  document.querySelectorAll('.thb-07 > .group').forEach(function (stage) {
    if (stage.dataset.bound) return; stage.dataset.bound = '1';
    var btn = stage.querySelector('button[aria-controls="thb07-menu"]');
    function set(open) {
      stage.toggleAttribute('data-open', open);
      btn.setAttribute('aria-expanded', String(open));
      btn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
    }
    btn.addEventListener('click', function () { set(btn.getAttribute('aria-expanded') !== 'true'); });
    stage.addEventListener('keydown', function (e) {
      if (e.key === 'Escape' && stage.hasAttribute('data-open')) { set(false); btn.focus(); }
    });
  });
})();

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-thb07-bg: #322a4d;
  --color-thb07-bg: oklch(0.22 0.045 285);
  --color-thb07-edge: #55496f;
  --color-thb07-edge: oklch(0.35 0.05 285);
  --color-thb07-ink: #f6f4fb;
  --color-thb07-ink: oklch(0.97 0.008 285);
  --color-thb07-mut: #c3bcd4;
  --color-thb07-mut: oklch(0.78 0.03 285);
  --color-thb07-acc: #6fd7e0;
  --color-thb07-acc: oklch(0.82 0.14 190);
  --color-thb07-blob1: #a03fd8;
  --color-thb07-blob1: oklch(0.62 0.23 310);
  --color-thb07-blob2: #4bc0d8;
  --color-thb07-blob2: oklch(0.75 0.16 200);
  --font-thb07-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb07-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-thb07: cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Keyframes are a rule, not a value — no utility form exists. */

@keyframes thb07-drift {
  from {
    translate: 0 0;
    scale: 1;
  }

  to {
    translate: 40px -30px;
    scale: 1.15;
  }
}
/* The one thing that MUST stay a feature query: without it, an engine with no
   backdrop-filter paints a 12%-alpha panel and page text crashes through the links. */

@supports not (backdrop-filter: blur(1px)) {
  .thb-07 .thb07-glass {
    background: oklch(0.25 0.04 280 / 0.94);
  }

  .thb-07 button[aria-controls="thb07-menu"] {
    background: oklch(0.3 0.05 280 / 0.85);
  }
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-07 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The glass recipe is the port's happiest case: backdrop-blur-* and backdrop-saturate-* COMPOSE into one backdrop-filter, and Tailwind emits the -webkit- prefix, so the two lines the CSS version has to keep in sync become two independent utilities.
  • The prefixed duplicate declaration disappears entirely — that is four lines of the original stylesheet gone with no loss of Safari support.
  • The ::after arrow on each link becomes a real <span aria-hidden> driven by a named group (group/l). Tailwind could do after:content-['…'], but a span is inspectable and cannot double an announcement.
  • The @keyframes drift and the @supports not fallback both stay in CSS. Keyframes are a rule, and a feature query touching two selectors is clearer than two long supports-* arbitrary variants.
  • The blobs' animation shorthand rides in one arbitrary animate-[…] value, and motion-reduce:animate-none stops the loop dead rather than slowing it.
  • isolate on the stage replaces the CSS version's isolation:isolate rule with a real utility — needed so the blurred blobs cannot bleed across demos on the collection page.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Glassmorphism Backdrop Blur Hamburger Navigation
Source: https://codefronts.com/navigation/tailwind-hamburger-menus/tailwind-glassmorphism-backdrop-blur-hamburger-navigation/

Real frosted glass, not grey-with-opacity &mdash; and Tailwind happens to have the exact utilities for it: backdrop-blur-[18px] backdrop-saturate-[1.7] compose into one backdrop-filter, no prefix juggling, no stacking order to remember. The stage runs drifting gradient blobs so you can see the glass working, and the mandatory @supports not fallback stays in CSS, where it belongs.
## HTML
```html
<section class="thb-07 w-full min-h-svh grid justify-center content-start bg-thb07-bg font-thb07-sans text-thb07-ink px-5 py-9" aria-label="Glassmorphism backdrop blur menu demo">
  <div class="group relative isolate w-[min(400px,88vw)] h-135 rounded-3xl overflow-hidden bg-thb07-bg border border-thb07-edge">
    <i class="absolute z-0 -left-20 top-15 w-75 h-75 rounded-full blur-[70px] bg-thb07-blob1 animate-[thb07-drift_11s_ease-in-out_infinite_alternate] motion-reduce:animate-none" aria-hidden="true"></i>
    <i class="absolute z-0 -right-17.5 -bottom-10 w-65 h-65 rounded-full blur-[70px] bg-thb07-blob2 animate-[thb07-drift_13s_ease-in-out_infinite_alternate-reverse] motion-reduce:animate-none" aria-hidden="true"></i>
    <header class="relative z-3 flex items-center justify-between h-18 px-5.5">
      <span class="text-[17px] font-bold tracking-[0.22em] uppercase">lumen</span>
      <button type="button" aria-expanded="false" aria-controls="thb07-menu" aria-label="Open menu" class="grid place-items-center w-11.5 h-11.5 rounded-[14px] border border-[oklch(1_0_0/0.28)] bg-[oklch(0.97_0.01_260/0.1)] backdrop-blur-[12px] backdrop-saturate-[1.6] text-thb07-ink cursor-pointer transition-[background,scale] duration-250 hover:bg-[oklch(0.97_0.01_260/0.2)] hover:scale-105 active:scale-95 focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-3">
        <span class="relative block w-4.5 h-3" aria-hidden="true">
          <i class="absolute left-0 top-0 w-4.5 h-0.5 rounded-sm bg-current transition-[translate,rotate] duration-300 group-data-open:translate-y-[5px] group-data-open:rotate-45 motion-reduce:transition-none"></i>
          <i class="absolute left-0 top-[5px] w-4.5 h-0.5 rounded-sm bg-current transition-[opacity] duration-200 group-data-open:opacity-0 motion-reduce:transition-none"></i>
          <i class="absolute left-0 top-2.5 w-4.5 h-0.5 rounded-sm bg-current transition-[translate,rotate] duration-300 group-data-open:-translate-y-[5px] group-data-open:-rotate-45 motion-reduce:transition-none"></i>
        </span>
      </button>
    </header>
    <div class="relative z-1 grid justify-items-start gap-3.5 px-6.5 py-11.5" aria-hidden="true">
      <h2 class="text-[37px] leading-[1.05] font-bold tracking-[-0.03em] text-balance">Light, refracted.</h2>
      <p class="max-w-[26ch] text-sm leading-relaxed text-thb07-mut text-pretty">Studio for luminous interfaces &mdash; glass, gradients and grain.</p>
      <div class="mt-2.5 px-4 py-2.25 rounded-full border border-[oklch(1_0_0/0.25)] bg-[oklch(0.97_0.01_260/0.08)] backdrop-blur-[8px] text-[11.5px] font-semibold tracking-[0.12em] uppercase">Scroll &darr;</div>
    </div>
    <nav id="thb07-menu" aria-label="Site" class="thb07-glass absolute z-2 inset-x-4 top-21.5 bottom-4 flex flex-col justify-center gap-0.5 px-6.5 rounded-[20px] bg-[oklch(0.97_0.01_260/0.12)] backdrop-blur-[18px] backdrop-saturate-[1.7] border border-[oklch(1_0_0/0.28)] shadow-[inset_0_1px_0_oklch(1_0_0/0.25),0_24px_48px_-20px_oklch(0.2_0.05_280/0.5)] opacity-0 -translate-y-3.5 scale-[0.98] invisible [transition:opacity_.35s,translate_.4s_var(--ease-thb07),scale_.4s_var(--ease-thb07),visibility_0s_.4s] group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:scale-100 group-data-open:visible group-data-open:[transition:opacity_.35s,translate_.4s_var(--ease-thb07),scale_.4s_var(--ease-thb07),visibility_0s_0s]">
      <a href="#work" style="--i:0" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Work</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#services" style="--i:1" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Services</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#about" style="--i:2" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>About</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <a href="#contact" style="--i:3" class="group/l flex items-center justify-between py-3.75 px-0.5 rounded-md border-b border-[oklch(1_0_0/0.14)] text-[28px] font-bold tracking-[-0.02em] text-thb07-ink no-underline opacity-0 translate-y-3 transition-[color,opacity,translate] duration-350 ease-thb07 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-4 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150"><span>Contact</span><span class="text-base opacity-0 -translate-x-1.5 translate-y-1 transition-[opacity,translate] duration-250 group-hover/l:opacity-100 group-hover/l:translate-x-0 group-hover/l:translate-y-0 group-focus-visible/l:opacity-100 group-focus-visible/l:translate-x-0 group-focus-visible/l:translate-y-0" aria-hidden="true">&#8599;</span></a>
      <footer style="--i:4" class="flex items-center justify-between mt-5.5 text-xs text-thb07-mut opacity-0 translate-y-3 transition-[opacity,translate] duration-350 ease-thb07 group-data-open:opacity-100 group-data-open:translate-y-0 group-data-open:[transition-delay:calc(100ms+var(--i)*55ms)] motion-reduce:translate-y-0 motion-reduce:duration-150">
        <span>&copy; 2026 lumen</span>
        <a href="#privacy" class="text-xs text-thb07-mut no-underline transition-[color] duration-200 hover:text-thb07-acc focus-visible:text-thb07-acc focus-visible:outline-2 focus-visible:outline-thb07-acc focus-visible:outline-offset-2">Privacy</a>
      </footer>
    </nav>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-thb07-bg: #322a4d;
  --color-thb07-bg: oklch(0.22 0.045 285);
  --color-thb07-edge: #55496f;
  --color-thb07-edge: oklch(0.35 0.05 285);
  --color-thb07-ink: #f6f4fb;
  --color-thb07-ink: oklch(0.97 0.008 285);
  --color-thb07-mut: #c3bcd4;
  --color-thb07-mut: oklch(0.78 0.03 285);
  --color-thb07-acc: #6fd7e0;
  --color-thb07-acc: oklch(0.82 0.14 190);
  --color-thb07-blob1: #a03fd8;
  --color-thb07-blob1: oklch(0.62 0.23 310);
  --color-thb07-blob2: #4bc0d8;
  --color-thb07-blob2: oklch(0.75 0.16 200);
  --font-thb07-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb07-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ease-thb07: cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* Keyframes are a rule, not a value — no utility form exists. */

@keyframes thb07-drift {
  from {
    translate: 0 0;
    scale: 1;
  }

  to {
    translate: 40px -30px;
    scale: 1.15;
  }
}
/* The one thing that MUST stay a feature query: without it, an engine with no
   backdrop-filter paints a 12%-alpha panel and page text crashes through the links. */

@supports not (backdrop-filter: blur(1px)) {
  .thb-07 .thb07-glass {
    background: oklch(0.25 0.04 280 / 0.94);
  }

  .thb-07 button[aria-controls="thb07-menu"] {
    background: oklch(0.3 0.05 280 / 0.85);
  }
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-07 {
  width: 100%;
  min-height: 100svh;
}
```

## JavaScript
```js
(function () {
  document.querySelectorAll('.thb-07 > .group').forEach(function (stage) {
    if (stage.dataset.bound) return; stage.dataset.bound = '1';
    var btn = stage.querySelector('button[aria-controls="thb07-menu"]');
    function set(open) {
      stage.toggleAttribute('data-open', open);
      btn.setAttribute('aria-expanded', String(open));
      btn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
    }
    btn.addEventListener('click', function () { set(btn.getAttribute('aria-expanded') !== 'true'); });
    stage.addEventListener('keydown', function (e) {
      if (e.key === 'Escape' && stage.hasAttribute('data-open')) { set(false); btn.focus(); }
    });
  });
})();
```

How this works

The whole material is one class list.

class="bg-[oklch(0.97_0.01_260/0.12)]
       backdrop-blur-[18px] backdrop-saturate-[1.7]
       border border-[oklch(1_0_0/0.28)]
       shadow-[inset_0_1px_0_oklch(1_0_0/0.25),0_24px_48px_-20px_oklch(0.2_0.05_280/0.5)]"

Every part earns its place. The background alpha must stay low (8–16%): most “glassmorphism” fails because a 60%-white background hides the blur entirely. backdrop-saturate-[1.7] is the secret ingredient — blur alone reads as fog, while boosting backdrop saturation makes colour bloom through the frost. The white-alpha border fakes glass's bright refracting edge, and the inset highlight sells a top-lit surface.

Composition is the port's win. In hand-written CSS you must remember that backdrop-filter is one property and a second declaration overwrites the first. Tailwind's backdrop-* utilities each set a variable that composes into one filter chain, so blur and saturate can be added, removed or overridden independently — including per breakpoint or per state.

Glass needs something behind it. Two blurred oklch blobs drift on a slow keyframe loop; in production your hero image or brand gradient plays that role. The @keyframes block stays in CSS, because keyframes are a rule, not a value.

The fallback is mandatory. @supports not (backdrop-filter: blur(1px)) raises the panel to 94% alpha. Without it, an engine with no support paints a 12%-alpha sheet with page text crashing straight through the links. Tailwind has a supports-* variant, but a two-selector feature query is cleaner as three lines of CSS than as two long arbitrary variants.

Make it yours

  • Frost intensity: backdrop-blur-[10px] is tinted glass, [18px] frosted, [28px] privacy glass. Keep saturate between 1.4 and 1.9 — beyond that whites go neon.
  • Dark glass: swap the background for bg-[oklch(0.2_0.03_280/0.35)] and the border for border-[oklch(1_0_0/0.14)]. Same physics, moodier panel.
  • Recolour the blob field through --color-thb07-blob1 / --color-thb07-blob2, or delete both and put a photo behind — the glass does not care.
  • Add grain, the 2026 finish: an after: layer with a tiny SVG-noise data URI at 4% opacity kills banding in the blur.
  • Slow the drift by editing the 11s/13s in the two animate-* arbitrary durations.

Gotchas — read before shipping

  • backdrop-blur-* only samples what is BEHIND the element. On a flat white page the glass is invisible — design the backdrop first.
  • An ancestor with filter, transform or will-change can flatten the backdrop root and break sampling in Safari. Transforming the glass panel itself (as here) is fine; transforming a wrapper is not.
  • Blur is per-pixel work. A viewport-sized sheet at backdrop-blur-[30px] measurably drops frame rate on mid-range Androids — keep glass partial-viewport or lower the radius with a breakpoint variant.
  • Do not put the @supports not fallback in an arbitrary variant. supports-* exists, but a feature query touching two selectors is clearer as CSS, and it must raise the alpha or the menu is unreadable.
  • Tailwind's backdrop-* utilities compose; a raw [backdrop-filter:…] arbitrary property does not, and will silently clobber any backdrop-* utility on the same element.
  • isolate on the stage is load-bearing: it keeps the blurred blobs inside the stage's own stacking context so they cannot bleed over neighbouring demos.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

backdrop-filter is Chrome 76+, Safari 9+ (prefixed — Tailwind emits the prefix for you) and Firefox 103+; the @supports not fallback covers everything older. The floor quoted here is Tailwind v4's own generated sheet.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Plain CSSno Tailwind surface

Search CodeFronts

Loading…