Tailwind v4MIT licensed

Tailwind Performance-Tuned Glass Navbar

The glass navbar built for a steady 60fps and clean Core Web Vitals: the expensive paint is boxed with [contain:layout_paint_style] and isolate, the compositor is hinted with will-change-transform on the one animating layer, the specular sweep animates transform only, and the blur is capped on purpose. The port keeps every one of those decisions visible on the element it applies to.

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="nbtw-22 grid place-items-center w-full min-h-svh p-5 font-nb22-sans bg-[linear-gradient(120deg,#2c3e50,#4ca1af_70%,#c4e0e5)]" aria-label="Performance tuned glass navbar demo">
  <nav class="relative overflow-hidden isolate [contain:layout_paint_style] flex flex-wrap items-center gap-x-4.5 gap-y-3 w-[min(740px,100%)] px-4.5 py-3.5 rounded-2xl text-white bg-[color-mix(in_oklab,white_12%,transparent)] border border-white/[0.34] shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_38px_-22px_rgba(0,0,0,.55)] backdrop-blur-[18px] backdrop-saturate-[1.7]" aria-label="Primary">
    <span class="absolute inset-0 z-0 pointer-events-none -translate-x-[120%] will-change-transform bg-[linear-gradient(105deg,transparent_40%,rgba(255,255,255,.35)_50%,transparent_60%)] animate-nb22-sweep motion-reduce:hidden" aria-hidden="true"></span>
    <span class="relative z-[1] text-base font-extrabold">⚡ Sixty</span>
    <div class="relative z-[1] flex flex-wrap gap-1">
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 aria-[current=page]:opacity-100 aria-[current=page]:bg-white/[0.18]" href="#nbtw-22" aria-current="page">Home</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Metrics</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Budget</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Docs</a>
    </div>
    <span class="relative z-[1] ms-auto text-[11px] font-bold tracking-[0.06em] uppercase tabular-nums text-white/70" aria-hidden="true">60 fps</span>
  </nav>
</section>
@import "tailwindcss";

@theme {
  --font-nb22-sans: system-ui, 'Segoe UI', sans-serif;
  --animate-nb22-sweep: nb22-sweep 5s ease-in-out infinite;
}
/* Transform only, with a long idle phase, so the specular pass stays on the
   compositor and never touches layout or paint. */

@keyframes nb22-sweep {
  0%,
    60% {
    transform: translateX(-120%);
  }

  100% {
    transform: translateX(120%);
  }
}

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 {
  --font-nb22-sans: system-ui, 'Segoe UI', sans-serif;
  --animate-nb22-sweep: nb22-sweep 5s ease-in-out infinite;
}
/* Transform only, with a long idle phase, so the specular pass stays on the
   compositor and never touches layout or paint. */

@keyframes nb22-sweep {
  0%,
    60% {
    transform: translateX(-120%);
  }

  100% {
    transform: translateX(120%);
  }
}

What changed in the port

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

  • Every performance decision is visible on the element it applies to: containment and isolation on the bar, will-change-transform on the sweep and nowhere else, the blur cap as a greppable number.
  • [contain:layout_paint_style] is an arbitrary property because containment is an engine hint, not a design token — and at these blur radii it is doing the heaviest lifting in the demo.
  • will-change-transform appears exactly once. Spread across a navbar it reserves memory per layer and makes things slower, which is the misuse this entry exists to demonstrate against.
  • The sweep animates translateX only, from an --animate-* theme entry, so retiming is one token edit and the animation never leaves the compositor.
  • motion-reduce:hidden removes the shimmer rather than slowing it — an ambient specular pass has no calm version worth keeping.
  • Containment establishes an independent formatting context, so absolutely-positioned children resolve against the bar. That is why the sweep and the links need no extra positioning parent.
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 Performance-Tuned Glass Navbar
Source: https://codefronts.com/navigation/tailwind-liquid-glass-navbars/tailwind-performance-tuned-glass-navbar/

The glass navbar built for a steady 60fps and clean Core Web Vitals: the expensive paint is boxed with [contain:layout_paint_style] and isolate, the compositor is hinted with will-change-transform on the one animating layer, the specular sweep animates transform only, and the blur is capped on purpose. The port keeps every one of those decisions visible on the element it applies to.
## HTML
```html
<section class="nbtw-22 grid place-items-center w-full min-h-svh p-5 font-nb22-sans bg-[linear-gradient(120deg,#2c3e50,#4ca1af_70%,#c4e0e5)]" aria-label="Performance tuned glass navbar demo">
  <nav class="relative overflow-hidden isolate [contain:layout_paint_style] flex flex-wrap items-center gap-x-4.5 gap-y-3 w-[min(740px,100%)] px-4.5 py-3.5 rounded-2xl text-white bg-[color-mix(in_oklab,white_12%,transparent)] border border-white/[0.34] shadow-[inset_0_1px_0_rgba(255,255,255,.5),0_16px_38px_-22px_rgba(0,0,0,.55)] backdrop-blur-[18px] backdrop-saturate-[1.7]" aria-label="Primary">
    <span class="absolute inset-0 z-0 pointer-events-none -translate-x-[120%] will-change-transform bg-[linear-gradient(105deg,transparent_40%,rgba(255,255,255,.35)_50%,transparent_60%)] animate-nb22-sweep motion-reduce:hidden" aria-hidden="true"></span>
    <span class="relative z-[1] text-base font-extrabold">⚡ Sixty</span>
    <div class="relative z-[1] flex flex-wrap gap-1">
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2 aria-[current=page]:opacity-100 aria-[current=page]:bg-white/[0.18]" href="#nbtw-22" aria-current="page">Home</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Metrics</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Budget</a>
      <a class="flex items-center min-h-10 px-3.5 rounded-[10px] no-underline text-white opacity-90 text-[14.5px] font-semibold transition-[background-color,opacity] duration-200 hover:opacity-100 hover:bg-white/[0.18] focus-visible:outline-2 focus-visible:outline-white focus-visible:outline-offset-2" href="#nbtw-22">Docs</a>
    </div>
    <span class="relative z-[1] ms-auto text-[11px] font-bold tracking-[0.06em] uppercase tabular-nums text-white/70" aria-hidden="true">60 fps</span>
  </nav>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --font-nb22-sans: system-ui, 'Segoe UI', sans-serif;
  --animate-nb22-sweep: nb22-sweep 5s ease-in-out infinite;
}
/* Transform only, with a long idle phase, so the specular pass stays on the
   compositor and never touches layout or paint. */

@keyframes nb22-sweep {
  0%,
    60% {
    transform: translateX(-120%);
  }

  100% {
    transform: translateX(120%);
  }
}
```

How this works

Containment is the headline. A backdrop-filter samples what is behind it, which can pull the whole page into a repaint. Declaring containment tells the engine the damage is bounded:

class="relative overflow-hidden isolate [contain:layout_paint_style]
       backdrop-blur-[18px] backdrop-saturate-[1.7]"

The sweep is compositor-only. One keyframe pair moving a gradient layer with translateX — no width, no left, no opacity on a large surface. Its animation is a theme entry, so retiming happens in one place:

--animate-nb22-sweep: nb22-sweep 5s ease-in-out infinite;
@keyframes nb22-sweep { 0%,60% { transform: translateX(-120%) } 100% { transform: translateX(120%) } }

will-change is a scalpel. It promotes the sweep to its own layer, and it appears exactly once. Applied to the bar or the links it would cost memory permanently for no gain — the classic misuse this demo is written to avoid.

The blur cap is a design decision. 18px is chosen against a device budget rather than aesthetics. Because it is a bracket value on the element, it is greppable: you can find every capped blur in a codebase and raise or lower the budget deliberately.

Make it yours

  • Raise or lower the blur cap to match your device budget; treat 24px as the ceiling on mid-tier mobile.
  • Retime the sweep in @theme, or lengthen its idle phase by moving the 60% keyframe stop.
  • Add content-visibility:auto to long offscreen content below the bar for extra savings; it pairs well with containment here.
  • Drop the sweep entirely for the cheapest possible glass bar — nothing else in the demo animates.
  • Toggle will-change just-in-time from JavaScript around interactions if you need it on more than one layer.

Gotchas — read before shipping

  • Never leave will-change on permanently across many elements. It reserves memory per layer, and a navbar full of promoted layers is slower, not faster.
  • Do not animate blur radius. Animate the transform or opacity of an already-blurred layer, which is what the sweep does.
  • contain: strict clips outer shadows. layout paint style is the combination that keeps the ambient shadow while still bounding the paint.
  • Containment changes layout semantics: a contained element establishes an independent formatting context, so absolutely-positioned children resolve against it.
  • An infinite shimmer on resting chrome has an attention cost as well as a frame cost. This one is slow, low-contrast, and gone under motion-reduce:.
  • Measure before and after. Containment and promotion are hypotheses about your page, not universal wins.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Tailwind v4 sets the floor. contain and will-change are widely supported and safely ignored where absent, so the performance work degrades to a plain glass bar rather than breaking.

Techniques used in this demo

Plain CSSno Tailwind surface

Search CodeFronts

Loading…