06 / 24
All 24 in 24 CSS Liquid Glass Navbars
- 01iOS 26 Floating Tab Bar
- 02macOS Tahoe Menu Bar
- 03Safari Toolbar (SVG Refraction)
- 04visionOS Glass Navbar
- 05Bottom Accessory / Mini-Player Bar
- 06Dynamic Island Navigation
- 07Tailwind Liquid Glass Navbar
- 08React Responsive Navbar (Burger)
- 09Next.js Sticky Glass Header
- 10Framer-Motion Spring Menu
- 11CSS Variables Theme Generator
- 12Bootstrap 5 Glass Navbar (Fluid)
- 13Scroll Opacity Sticky Navbar
- 14Inner-Glow Hover Links
- 15Cursor-Warp Interactive Nav
- 16Animated Gradient Blobs Navbar
- 17Sliding Capsule Active Tab
- 18Reflective Glass Sidebar
- 19Firefox Fallback Navbar
- 20High-Contrast Accessible Navbar
- 21Light / Dark Mode Navbar
- 22Performance-Tuned Navbar
- 23Minimalist Dual-Border Header
- 24Responsive Sidebar to Bottom Tabs
Dynamic Island Navigation
A compact glass pill, in the spirit of the Dynamic Island, that morphs organically between states: it rests as a slim capsule, then fluidly stretches and reveals contextual controls when activated. The width, radius and content animate on one spring so the shape feels liquid, not switched.
Build interactive UI like this from scratch: 20 HTML, CSS & JavaScript projects
ZTM · JavaScript Web Projects · 30‑day money-back guarantee · Affiliate link
The code
<section class="nb-06" aria-label="Dynamic Island navigation demo">
<p class="nb-06__hint">Tap the island to morph it open ↑</p>
<div class="nb-06__island" id="nb-06-island" data-state="idle">
<button class="nb-06__trigger" id="nb-06-trigger" type="button" aria-expanded="false" aria-controls="nb-06-panel">
<span class="nb-06__pulse" aria-hidden="true"></span><span class="nb-06__label">Lumen</span>
</button>
<div class="nb-06__panel" id="nb-06-panel" role="group" aria-label="Quick navigation">
<a class="nb-06__act" href="#nb-06" aria-current="page">Home</a>
<a class="nb-06__act" href="#nb-06">Search</a>
<a class="nb-06__act" href="#nb-06">Alerts</a>
<a class="nb-06__act" href="#nb-06">You</a>
</div>
</div>
</section><section class="nb-06" aria-label="Dynamic Island navigation demo">
<p class="nb-06__hint">Tap the island to morph it open ↑</p>
<div class="nb-06__island" id="nb-06-island" data-state="idle">
<button class="nb-06__trigger" id="nb-06-trigger" type="button" aria-expanded="false" aria-controls="nb-06-panel">
<span class="nb-06__pulse" aria-hidden="true"></span><span class="nb-06__label">Lumen</span>
</button>
<div class="nb-06__panel" id="nb-06-panel" role="group" aria-label="Quick navigation">
<a class="nb-06__act" href="#nb-06" aria-current="page">Home</a>
<a class="nb-06__act" href="#nb-06">Search</a>
<a class="nb-06__act" href="#nb-06">Alerts</a>
<a class="nb-06__act" href="#nb-06">You</a>
</div>
</div>
</section>.nb-06,
.nb-06 *,
.nb-06 *::before,
.nb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-06 {
--accent: oklch(0.7 0.18 150);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: 60px;
font-family: 'Segoe UI',system-ui,sans-serif;
background: radial-gradient(circle at 30% 30%,#0f3d2e,#05100b 70%),url('https://picsum.photos/seed/nb06/1000/700') center/cover;
background-blend-mode: overlay;
}
.nb-06__hint {
color: rgba(255,255,255,.75);
font-size: 14px;
margin-bottom: 20px;
}
.nb-06__island {
position: relative;
overflow: hidden;
width: 184px;
height: 46px;
border-radius: 999px;
isolation: isolate;
background: color-mix(in oklab,black 40%,transparent);
border: 1px solid rgba(255,255,255,.22);
box-shadow: inset 0 1px 0 rgba(255,255,255,.4),0 24px 50px -22px rgba(0,0,0,.8);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
transition: width .55s cubic-bezier(.34,1.4,.5,1),height .55s cubic-bezier(.34,1.4,.5,1),border-radius .55s;
}
.nb-06__island[data-state="expanded"] {
width: 300px;
height: 152px;
border-radius: 30px;
}
.nb-06__trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
border: 0;
background: none;
color: #fff;
font-family: inherit;
font-size: 15px;
font-weight: 700;
line-height: 1;
cursor: pointer;
z-index: 2;
}
.nb-06__label {
display: inline-block;
line-height: 1;
}
.nb-06__pulse {
width: 11px;
height: 11px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 12px var(--accent);
animation: nb-06-pulse 2.4s ease-in-out infinite;
flex: none;
}
@keyframes nb-06-pulse {
50% {
transform: scale(1.35);
opacity: .6;
}
}
.nb-06__panel {
position: absolute;
top: 46px;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 0 16px 16px;
opacity: 0;
pointer-events: none;
transition: opacity .2s;
}
.nb-06__island[data-state="expanded"] .nb-06__panel {
opacity: 1;
pointer-events: auto;
transition: opacity .3s .2s;
}
.nb-06__act {
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
text-decoration: none;
color: #fff;
font-size: 14px;
font-weight: 600;
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.16);
transition: background .2s;
}
.nb-06__act[aria-current] {
background: var(--accent);
color: #04120b;
}
.nb-06__act:hover {
background: rgba(255,255,255,.2);
}
.nb-06__act:focus-visible,
.nb-06__trigger:focus-visible {
outline: 2px solid #fff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.nb-06__island {
transition: none;
}
.nb-06__pulse {
animation: none;
}
}.nb-06,
.nb-06 *,
.nb-06 *::before,
.nb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-06 {
--accent: oklch(0.7 0.18 150);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: 60px;
font-family: 'Segoe UI',system-ui,sans-serif;
background: radial-gradient(circle at 30% 30%,#0f3d2e,#05100b 70%),url('https://picsum.photos/seed/nb06/1000/700') center/cover;
background-blend-mode: overlay;
}
.nb-06__hint {
color: rgba(255,255,255,.75);
font-size: 14px;
margin-bottom: 20px;
}
.nb-06__island {
position: relative;
overflow: hidden;
width: 184px;
height: 46px;
border-radius: 999px;
isolation: isolate;
background: color-mix(in oklab,black 40%,transparent);
border: 1px solid rgba(255,255,255,.22);
box-shadow: inset 0 1px 0 rgba(255,255,255,.4),0 24px 50px -22px rgba(0,0,0,.8);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
transition: width .55s cubic-bezier(.34,1.4,.5,1),height .55s cubic-bezier(.34,1.4,.5,1),border-radius .55s;
}
.nb-06__island[data-state="expanded"] {
width: 300px;
height: 152px;
border-radius: 30px;
}
.nb-06__trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
border: 0;
background: none;
color: #fff;
font-family: inherit;
font-size: 15px;
font-weight: 700;
line-height: 1;
cursor: pointer;
z-index: 2;
}
.nb-06__label {
display: inline-block;
line-height: 1;
}
.nb-06__pulse {
width: 11px;
height: 11px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 12px var(--accent);
animation: nb-06-pulse 2.4s ease-in-out infinite;
flex: none;
}
@keyframes nb-06-pulse {
50% {
transform: scale(1.35);
opacity: .6;
}
}
.nb-06__panel {
position: absolute;
top: 46px;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 0 16px 16px;
opacity: 0;
pointer-events: none;
transition: opacity .2s;
}
.nb-06__island[data-state="expanded"] .nb-06__panel {
opacity: 1;
pointer-events: auto;
transition: opacity .3s .2s;
}
.nb-06__act {
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
text-decoration: none;
color: #fff;
font-size: 14px;
font-weight: 600;
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.16);
transition: background .2s;
}
.nb-06__act[aria-current] {
background: var(--accent);
color: #04120b;
}
.nb-06__act:hover {
background: rgba(255,255,255,.2);
}
.nb-06__act:focus-visible,
.nb-06__trigger:focus-visible {
outline: 2px solid #fff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.nb-06__island {
transition: none;
}
.nb-06__pulse {
animation: none;
}
}(() => {
const island = document.querySelector('#nb-06-island');
const trigger = document.querySelector('#nb-06-trigger');
const panel = document.querySelector('#nb-06-panel');
if (!island || !trigger) return;
function set(open){
island.dataset.state = open ? 'expanded' : 'idle';
trigger.setAttribute('aria-expanded', String(open));
if (open) panel.querySelector('a').focus();
}
trigger.addEventListener('click', () => set(island.dataset.state !== 'expanded'));
island.addEventListener('keydown', e => { if (e.key === 'Escape'){ set(false); trigger.focus(); } });
})();(() => {
const island = document.querySelector('#nb-06-island');
const trigger = document.querySelector('#nb-06-trigger');
const panel = document.querySelector('#nb-06-panel');
if (!island || !trigger) return;
function set(open){
island.dataset.state = open ? 'expanded' : 'idle';
trigger.setAttribute('aria-expanded', String(open));
if (open) panel.querySelector('a').focus();
}
trigger.addEventListener('click', () => set(island.dataset.state !== 'expanded'));
island.addEventListener('keydown', e => { if (e.key === 'Escape'){ set(false); trigger.focus(); } });
})();Here's a working CSS Liquid Glass Navbar 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: Dynamic Island Navigation
Source: https://codefronts.com/navigation/css-liquid-glass-navbars/dynamic-island-navigation/
A compact glass pill, in the spirit of the Dynamic Island, that morphs organically between states: it rests as a slim capsule, then fluidly stretches and reveals contextual controls when activated. The width, radius and content animate on one spring so the shape feels liquid, not switched.
## HTML
```html
<section class="nb-06" aria-label="Dynamic Island navigation demo">
<p class="nb-06__hint">Tap the island to morph it open ↑</p>
<div class="nb-06__island" id="nb-06-island" data-state="idle">
<button class="nb-06__trigger" id="nb-06-trigger" type="button" aria-expanded="false" aria-controls="nb-06-panel">
<span class="nb-06__pulse" aria-hidden="true"></span><span class="nb-06__label">Lumen</span>
</button>
<div class="nb-06__panel" id="nb-06-panel" role="group" aria-label="Quick navigation">
<a class="nb-06__act" href="#nb-06" aria-current="page">Home</a>
<a class="nb-06__act" href="#nb-06">Search</a>
<a class="nb-06__act" href="#nb-06">Alerts</a>
<a class="nb-06__act" href="#nb-06">You</a>
</div>
</div>
</section>
```
## CSS
```css
.nb-06,
.nb-06 *,
.nb-06 *::before,
.nb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-06 {
--accent: oklch(0.7 0.18 150);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: 60px;
font-family: 'Segoe UI',system-ui,sans-serif;
background: radial-gradient(circle at 30% 30%,#0f3d2e,#05100b 70%),url('https://picsum.photos/seed/nb06/1000/700') center/cover;
background-blend-mode: overlay;
}
.nb-06__hint {
color: rgba(255,255,255,.75);
font-size: 14px;
margin-bottom: 20px;
}
.nb-06__island {
position: relative;
overflow: hidden;
width: 184px;
height: 46px;
border-radius: 999px;
isolation: isolate;
background: color-mix(in oklab,black 40%,transparent);
border: 1px solid rgba(255,255,255,.22);
box-shadow: inset 0 1px 0 rgba(255,255,255,.4),0 24px 50px -22px rgba(0,0,0,.8);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
transition: width .55s cubic-bezier(.34,1.4,.5,1),height .55s cubic-bezier(.34,1.4,.5,1),border-radius .55s;
}
.nb-06__island[data-state="expanded"] {
width: 300px;
height: 152px;
border-radius: 30px;
}
.nb-06__trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
border: 0;
background: none;
color: #fff;
font-family: inherit;
font-size: 15px;
font-weight: 700;
line-height: 1;
cursor: pointer;
z-index: 2;
}
.nb-06__label {
display: inline-block;
line-height: 1;
}
.nb-06__pulse {
width: 11px;
height: 11px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 12px var(--accent);
animation: nb-06-pulse 2.4s ease-in-out infinite;
flex: none;
}
@keyframes nb-06-pulse {
50% {
transform: scale(1.35);
opacity: .6;
}
}
.nb-06__panel {
position: absolute;
top: 46px;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 0 16px 16px;
opacity: 0;
pointer-events: none;
transition: opacity .2s;
}
.nb-06__island[data-state="expanded"] .nb-06__panel {
opacity: 1;
pointer-events: auto;
transition: opacity .3s .2s;
}
.nb-06__act {
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
text-decoration: none;
color: #fff;
font-size: 14px;
font-weight: 600;
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.16);
transition: background .2s;
}
.nb-06__act[aria-current] {
background: var(--accent);
color: #04120b;
}
.nb-06__act:hover {
background: rgba(255,255,255,.2);
}
.nb-06__act:focus-visible,
.nb-06__trigger:focus-visible {
outline: 2px solid #fff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.nb-06__island {
transition: none;
}
.nb-06__pulse {
animation: none;
}
}
```
## JavaScript
```js
(() => {
const island = document.querySelector('#nb-06-island');
const trigger = document.querySelector('#nb-06-trigger');
const panel = document.querySelector('#nb-06-panel');
if (!island || !trigger) return;
function set(open){
island.dataset.state = open ? 'expanded' : 'idle';
trigger.setAttribute('aria-expanded', String(open));
if (open) panel.querySelector('a').focus();
}
trigger.addEventListener('click', () => set(island.dataset.state !== 'expanded'));
island.addEventListener('keydown', e => { if (e.key === 'Escape'){ set(false); trigger.focus(); } });
})();
```Here's a working CSS Liquid Glass Navbar 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: Dynamic Island Navigation
Source: https://codefronts.com/navigation/css-liquid-glass-navbars/dynamic-island-navigation/
A compact glass pill, in the spirit of the Dynamic Island, that morphs organically between states: it rests as a slim capsule, then fluidly stretches and reveals contextual controls when activated. The width, radius and content animate on one spring so the shape feels liquid, not switched.
## HTML
```html
<section class="nb-06" aria-label="Dynamic Island navigation demo">
<p class="nb-06__hint">Tap the island to morph it open ↑</p>
<div class="nb-06__island" id="nb-06-island" data-state="idle">
<button class="nb-06__trigger" id="nb-06-trigger" type="button" aria-expanded="false" aria-controls="nb-06-panel">
<span class="nb-06__pulse" aria-hidden="true"></span><span class="nb-06__label">Lumen</span>
</button>
<div class="nb-06__panel" id="nb-06-panel" role="group" aria-label="Quick navigation">
<a class="nb-06__act" href="#nb-06" aria-current="page">Home</a>
<a class="nb-06__act" href="#nb-06">Search</a>
<a class="nb-06__act" href="#nb-06">Alerts</a>
<a class="nb-06__act" href="#nb-06">You</a>
</div>
</div>
</section>
```
## CSS
```css
.nb-06,
.nb-06 *,
.nb-06 *::before,
.nb-06 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.nb-06 {
--accent: oklch(0.7 0.18 150);
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: 60px;
font-family: 'Segoe UI',system-ui,sans-serif;
background: radial-gradient(circle at 30% 30%,#0f3d2e,#05100b 70%),url('https://picsum.photos/seed/nb06/1000/700') center/cover;
background-blend-mode: overlay;
}
.nb-06__hint {
color: rgba(255,255,255,.75);
font-size: 14px;
margin-bottom: 20px;
}
.nb-06__island {
position: relative;
overflow: hidden;
width: 184px;
height: 46px;
border-radius: 999px;
isolation: isolate;
background: color-mix(in oklab,black 40%,transparent);
border: 1px solid rgba(255,255,255,.22);
box-shadow: inset 0 1px 0 rgba(255,255,255,.4),0 24px 50px -22px rgba(0,0,0,.8);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
transition: width .55s cubic-bezier(.34,1.4,.5,1),height .55s cubic-bezier(.34,1.4,.5,1),border-radius .55s;
}
.nb-06__island[data-state="expanded"] {
width: 300px;
height: 152px;
border-radius: 30px;
}
.nb-06__trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
border: 0;
background: none;
color: #fff;
font-family: inherit;
font-size: 15px;
font-weight: 700;
line-height: 1;
cursor: pointer;
z-index: 2;
}
.nb-06__label {
display: inline-block;
line-height: 1;
}
.nb-06__pulse {
width: 11px;
height: 11px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 12px var(--accent);
animation: nb-06-pulse 2.4s ease-in-out infinite;
flex: none;
}
@keyframes nb-06-pulse {
50% {
transform: scale(1.35);
opacity: .6;
}
}
.nb-06__panel {
position: absolute;
top: 46px;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 0 16px 16px;
opacity: 0;
pointer-events: none;
transition: opacity .2s;
}
.nb-06__island[data-state="expanded"] .nb-06__panel {
opacity: 1;
pointer-events: auto;
transition: opacity .3s .2s;
}
.nb-06__act {
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
text-decoration: none;
color: #fff;
font-size: 14px;
font-weight: 600;
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.16);
transition: background .2s;
}
.nb-06__act[aria-current] {
background: var(--accent);
color: #04120b;
}
.nb-06__act:hover {
background: rgba(255,255,255,.2);
}
.nb-06__act:focus-visible,
.nb-06__trigger:focus-visible {
outline: 2px solid #fff;
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
.nb-06__island {
transition: none;
}
.nb-06__pulse {
animation: none;
}
}
```
## JavaScript
```js
(() => {
const island = document.querySelector('#nb-06-island');
const trigger = document.querySelector('#nb-06-trigger');
const panel = document.querySelector('#nb-06-panel');
if (!island || !trigger) return;
function set(open){
island.dataset.state = open ? 'expanded' : 'idle';
trigger.setAttribute('aria-expanded', String(open));
if (open) panel.querySelector('a').focus();
}
trigger.addEventListener('click', () => set(island.dataset.state !== 'expanded'));
island.addEventListener('keydown', e => { if (e.key === 'Escape'){ set(false); trigger.focus(); } });
})();
```How this works
A single fixed pill toggles a data-state attribute (idle / expanded) on click or focus. CSS transitions animate width, height, border-radius and the opacity of the hidden controls with one spring easing, so the container appears to physically morph. backdrop-filter keeps it glassy against the background.
The pill is a real button (aria-expanded), the revealed region is labelled, Escape collapses it, and focus is moved into the expanded controls — a keyboard user gets the same morph.
Make it yours
- Add more states (call / timer / nav) by extending the data-state switch.
- Tune the morph feel via the transition timing on width/radius.
- Anchor top-centre for a true notch-island position.
Gotchas — read before shipping
- Animate width/height with fixed values or max-width, not auto, so the transition runs.
- Keep the collapsed pill a real button with a label so it's operable before expanding.
- Return focus to the trigger on collapse.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.2+ | 113+ | 111+ |
Floor set by oklch(), color-mix(), backdrop-filter as this demo is written. The core technique itself goes back further — Chrome 76+.
Morph is progressive; without JS the pill stays in its expanded, fully usable nav state.