Tailwind v4MIT licensed

Tailwind High-Contrast Accessible Glass Navbar

A glass navbar that refuses to trade beauty for accessibility — and the port where two whole media-query blocks become two variants. forced-colors: maps the bar to system colours; contrast-more: darkens the scrim. A semi-opaque scrim under the frost guarantees 4.5:1 over a bright, busy photograph, and the focus ring is a 4px high-contrast outline.

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-20 grid place-items-center w-full min-h-svh p-5 font-nb20-sans bg-[linear-gradient(120deg,#f7971e,#ffd200_60%,#f7f7f7),url('https://picsum.photos/seed/nb20bright/1000/700')] bg-center bg-cover [background-blend-mode:overlay]" aria-label="High contrast accessible glass navbar demo">
  <nav class="relative flex flex-wrap items-center gap-x-5 gap-y-3 w-[min(760px,100%)] px-4.5 py-3.5 rounded-2xl text-white bg-[rgba(18,20,28,.66)] border border-white/50 shadow-[inset_0_1px_0_rgba(255,255,255,.55),inset_0_0_0_1px_rgba(0,0,0,.25),0_18px_40px_-22px_rgba(0,0,0,.7)] backdrop-blur-[16px] backdrop-saturate-150 contrast-more:bg-[rgba(10,10,16,.9)] forced-colors:bg-[Canvas] forced-colors:border-[CanvasText] forced-colors:text-[CanvasText]" aria-label="Primary">
    <span class="text-base font-extrabold [text-shadow:0_1px_2px_rgba(0,0,0,.6)]">◆ Access</span>
    <div class="flex flex-wrap gap-1 ms-auto">
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 aria-[current=page]:bg-white/[0.24] aria-[current=page]:underline aria-[current=page]:underline-offset-4 forced-colors:text-[LinkText]" href="#nbtw-20" aria-current="page">Home</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Guides</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Tools</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Contact</a>
    </div>
    <button class="min-h-11 px-4.5 rounded-[10px] border-2 border-white bg-white text-[#101018] text-[15px] font-extrabold cursor-pointer focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:bg-[ButtonFace] forced-colors:text-[ButtonText] forced-colors:border-[ButtonText]" type="button">Get help</button>
  </nav>
</section>
@import "tailwindcss";

@theme {
  --font-nb20-sans: system-ui, 'Segoe UI', sans-serif;
}

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-nb20-sans: system-ui, 'Segoe UI', sans-serif;
}

What changed in the port

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

  • Two whole media-query blocks become two variants: forced-colors: and contrast-more:. The accessibility layer stops being a footnote at the bottom of a stylesheet and becomes part of each element's own description.
  • The scrim, not the blur, carries the contrast. backdrop-filter softens a backdrop but guarantees nothing about its brightest pixel.
  • System colour keywords (Canvas, CanvasText, LinkText, ButtonFace, ButtonText) are used inside forced-colors: arbitrary values, which is the only place they are meaningful.
  • The active link is marked three ways — background, underline and aria-current — so nothing about it depends on colour perception.
  • The focus ring is 4px of saturated yellow with an offset, hard-coded rather than inherited, because a faint inherited ring is how keyboard users get lost on glass.
  • In forced-colors mode the glass is effectively gone. That tier is designed as a flat, system-coloured bar, because pretending otherwise is how high-contrast users get an unreadable slab.
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 High-Contrast Accessible Glass Navbar
Source: https://codefronts.com/navigation/tailwind-liquid-glass-navbars/tailwind-high-contrast-accessible-glass-navbar/

A glass navbar that refuses to trade beauty for accessibility &mdash; and the port where two whole media-query blocks become two variants. forced-colors: maps the bar to system colours; contrast-more: darkens the scrim. A semi-opaque scrim under the frost guarantees 4.5:1 over a bright, busy photograph, and the focus ring is a 4px high-contrast outline.
## HTML
```html
<section class="nbtw-20 grid place-items-center w-full min-h-svh p-5 font-nb20-sans bg-[linear-gradient(120deg,#f7971e,#ffd200_60%,#f7f7f7),url('https://picsum.photos/seed/nb20bright/1000/700')] bg-center bg-cover [background-blend-mode:overlay]" aria-label="High contrast accessible glass navbar demo">
  <nav class="relative flex flex-wrap items-center gap-x-5 gap-y-3 w-[min(760px,100%)] px-4.5 py-3.5 rounded-2xl text-white bg-[rgba(18,20,28,.66)] border border-white/50 shadow-[inset_0_1px_0_rgba(255,255,255,.55),inset_0_0_0_1px_rgba(0,0,0,.25),0_18px_40px_-22px_rgba(0,0,0,.7)] backdrop-blur-[16px] backdrop-saturate-150 contrast-more:bg-[rgba(10,10,16,.9)] forced-colors:bg-[Canvas] forced-colors:border-[CanvasText] forced-colors:text-[CanvasText]" aria-label="Primary">
    <span class="text-base font-extrabold [text-shadow:0_1px_2px_rgba(0,0,0,.6)]">◆ Access</span>
    <div class="flex flex-wrap gap-1 ms-auto">
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 aria-[current=page]:bg-white/[0.24] aria-[current=page]:underline aria-[current=page]:underline-offset-4 forced-colors:text-[LinkText]" href="#nbtw-20" aria-current="page">Home</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Guides</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Tools</a>
      <a class="flex items-center min-h-11 px-[15px] rounded-[10px] no-underline text-white text-[15px] font-semibold [text-shadow:0_1px_2px_rgba(0,0,0,.55)] transition-colors duration-200 hover:bg-white/[0.18] focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:text-[LinkText]" href="#nbtw-20">Contact</a>
    </div>
    <button class="min-h-11 px-4.5 rounded-[10px] border-2 border-white bg-white text-[#101018] text-[15px] font-extrabold cursor-pointer focus-visible:outline-4 focus-visible:outline-[#ffe000] focus-visible:outline-offset-2 forced-colors:bg-[ButtonFace] forced-colors:text-[ButtonText] forced-colors:border-[ButtonText]" type="button">Get help</button>
  </nav>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --font-nb20-sans: system-ui, 'Segoe UI', sans-serif;
}
```

How this works

Two media blocks become two variants. The accessibility layer stops being something at the bottom of a stylesheet and becomes part of the element's own description:

class="bg-[rgba(18,20,28,.66)] backdrop-blur-[16px]
       forced-colors:bg-[Canvas] forced-colors:border-[CanvasText]
       contrast-more:bg-[rgba(10,10,16,.9)]"

The scrim does the contrast work, not the blur. backdrop-filter softens whatever is behind it but guarantees nothing: a bright highlight in a photograph can still put white text at 2:1. A semi-opaque dark scrim under the frost is what makes 4.5:1 a promise instead of a hope.

Forced-colors mode needs real keywords. Canvas, CanvasText, LinkText, ButtonFace and ButtonText are system colours the OS controls. Mapping to them is how the bar survives a high-contrast theme instead of turning into an unreadable slab — and in that mode the glass is simply gone, which is correct.

Nothing relies on colour alone. The active link carries a background, an underline and aria-current; every target is at least 44px; and the focus ring is 4px of saturated yellow with an offset, chosen to be visible against both the glass and the system-colour tier.

Make it yours

  • Tune the scrim alpha to hit your exact measured ratio against your real background image, not a placeholder.
  • Thicken the focus ring further (outline-[6px]) or add more offset for low-vision users; nothing else needs to change.
  • Swap the scrim for a light one in dark-on-light contexts and flip the text colour with it.
  • Add forced-colors: twins for any decorative layer you introduce — usually by hiding it, since decorations do not map to system colours.
  • Keep the underline on the active link even if you dislike it; it is the part of this design that survives greyscale and colour blindness.

Gotchas — read before shipping

  • Never rely on blur for contrast. Always back text with a scrim solid enough to hold your ratio at the worst pixel of the backdrop.
  • System colour keywords only mean anything inside forced-colors:. Elsewhere they resolve to defaults that will surprise you.
  • Do not inherit a faint focus ring from a design system. This demo hard-codes a loud one on purpose.
  • contrast-more: maps to prefers-contrast: more, which is not the same as forced-colors mode — support both, as this demo does.
  • 44px minimum targets apply to the links too, not just the button; min-h-11 is on every one of them here.
  • In forced-colors mode backdrop-filter effectively disappears. Design the tier as though the glass is not there, because it is not.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Tailwind v4 sets the floor. The scrim, dual borders and focus ring work everywhere inside it; backdrop-filter is the only progressive part, and forced-colors / prefers-contrast are honoured where the OS exposes them.

Techniques used in this demo

HTML & JSno Tailwind involved

Search CodeFronts

Loading…