08 / 11
All 11 in 11 Tailwind CSS Glassmorphic Navbars
- 01Tailwind Glassmorphism Navbar for SaaS Landing Pages
- 02Tailwind Transparent Navbar That Turns Frosted Glass on Scroll
- 03Dark Mode Cyberpunk Neon Glass Navbar in Tailwind CSS
- 04Tailwind Floating Pill Navbar with Glass Effect
- 05Tailwind Glassmorphism Dropdown & Mega Menu Navbar
- 06Tailwind Mobile Hamburger Menu with Glass Off-Canvas Drawer
- 07Lightweight Tailwind Sticky Header with Backdrop Blur (Zero JS)
- 08Tailwind Animated Gradient Border Glass Navbar
- 09Accessible Tailwind Glassmorphism Navbar (WCAG AA)
- 10Next.js Tailwind Glass Header with Framer Motion
- 11Minimalist Tailwind Glass Navbar for Portfolios
Tailwind Animated Gradient Border Glass Navbar
An iridescent conic-gradient border chasing around a dark glass bar, with a soft blurred glow of the same gradient underneath. The angle is a registered @property (the one thing that must stay CSS), the spin is an @theme animation token, and the ring itself is a masked before: layer.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<div class="tgn-08 w-full min-h-svh bg-tgn08-night bg-[radial-gradient(90%_120%_at_15%_0%,var(--color-tgn08-dusk),var(--color-tgn08-night)_70%)] font-tgn08-sans">
<div class="relative h-svh overflow-y-auto scroll-smooth px-4 py-5 sm:px-6 sm:py-7">
<header class="group/frame sticky top-0 z-10 rounded-2xl p-0.5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:p-0.5 before:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] before:[mask:linear-gradient(#000_0_0)_content-box_exclude,linear-gradient(#000_0_0)] before:animate-tgn08-spin after:pointer-events-none after:absolute after:inset-0 after:-z-10 after:rounded-[inherit] after:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] after:opacity-40 after:blur-xl after:animate-tgn08-spin after:transition-opacity after:duration-300 hover:after:opacity-75 focus-within:after:opacity-75 motion-reduce:before:animate-none motion-reduce:after:animate-none">
<div class="relative flex h-15 items-center gap-5 rounded-[14px] bg-tgn08-glass/60 px-5 backdrop-blur-lg backdrop-saturate-[1.6] not-supports-[backdrop-filter:blur(1px)]:bg-tgn08-glass max-sm:h-14 max-sm:gap-2 max-sm:px-3">
<a class="flex items-center gap-2 rounded-md text-lg font-bold tracking-[-0.02em] text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c" href="#"><span aria-hidden="true" class="size-4 rotate-45 rounded-[3px] bg-[conic-gradient(from_45deg,var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))]"></span>Prism</a>
<nav class="ml-auto" aria-label="Primary">
<ul class="flex gap-1 max-sm:gap-0">
<li><a href="#" aria-current="page" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Studio</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Gallery</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Shop</a></li>
<li class="max-[400px]:hidden"><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Info</a></li>
</ul>
</nav>
</div>
</header>
<div class="mx-auto max-w-2xl px-2 pt-12 pb-20 text-tgn08-ink/88 [&_p]:mb-3.5 [&_p]:text-[15px]/[1.65] [&_p]:font-medium [&_p]:text-pretty [&_:is(h1,h2,h3)]:text-balance [&_h2]:mt-5 [&_h2]:mb-3.5 [&_h2]:text-[22px]/[1.2] [&_h2]:font-extrabold [&_h2]:tracking-[-0.015em] [&_h3]:mt-8 [&_h3]:mb-3 [&_h3]:text-lg/[1.25] [&_h3]:font-bold [&_h3]:tracking-[-0.01em] [&_:is(h2,h3)]:text-white [&_code]:rounded-md [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-tgn08-mono [&_code]:text-[12.5px] [&_code]:font-medium [&_code]:border [&_code]:border-white/18 [&_code]:bg-white/10 [&_code]:text-white">
<h2>Watch the border chase § the frame stays lit while you scroll</h2>
<p>The sticky frame keeps its rotating gradient border visible the whole way down the page. Because <code>@property --angle</code> is registered as a typed <code><angle></code>, CSS can actually interpolate it — untyped custom properties snap between values.</p>
<p>A pseudo-element sits behind the bar, one <code>--border-width</code> larger on every side, filled with a <code>conic-gradient(from var(--angle), …)</code>. The gradient rotates through 360deg; the only visible slice is the thin frame peeking around the glass bar in front.</p>
<p>The gradient stops ARE the palette. Two or three saturated hues at a few positions read as a chasing highlight; a full oklch hue wheel reads as an iridescent ring.</p>
<h3>The @property gate</h3>
<p>Registered custom properties are the entire reason this animation works. Without <code>@property</code>, the browser treats <code>--angle</code> as a plain string and cannot interpolate it — the keyframe animation would snap from 0deg to 360deg with no intermediate frames.</p>
<p>The registration tells the browser: this variable is an <code><angle></code> type, has an initial value of 0deg, and does not inherit. Now CSS can smoothly tween it, and the conic-gradient re-renders continuously.</p>
<p>This is CSS Houdini territory — the ability to define new typed primitives. Baseline support arrived in 2024 (Firefox 128 was the last major engine). For older browsers, the border shows a static gradient at the initial angle — a graceful fallback that still looks intentional.</p>
<h3>Mask-composite is the second half of the trick</h3>
<p>The gradient pseudo-element fills the entire frame area, not just the border. To reveal only the border, use <code>mask-composite:exclude</code> with two masks: one for the outer edge, one for the inner content area. The subtraction leaves only the ring.</p>
<p>This is the same technique CSS Tricks documented for gradient borders. Combined with the rotating <code>--angle</code>, it creates the lit-edge illusion without any actual border property.</p>
<p>The alternative — a real <code>border-image</code> with an animated gradient — doesn't work because <code>border-image</code> cannot animate its gradient angle directly. The conic + mask + <code>@property</code> route is the only way in current CSS.</p>
<h3>Polish moves</h3>
<p>Add a <code>filter:blur(6px)</code> on the gradient pseudo-element to convert the crisp border into a soft glow halo. Or a matching <code>box-shadow</code> to bleed the colour outward for a bigger lit-edge feel.</p>
<p>Speed via the animation duration: 6s is an elegant drift, 2s is an energetic gamer-RGB spin. Freeze one segment as an accent by dropping the animation entirely for a static gradient border.</p>
<p>Animate <code>--angle</code> on hover only rather than continuously. The border comes alive when the user engages the nav and stays quiet otherwise — better for battery on mobile and less visually noisy on long-form content pages.</p>
<p>A constantly-spinning border repaints every frame — respect <code>prefers-reduced-motion</code> and consider pausing it when off-screen for battery.</p>
<h3>Where iridescent borders belong</h3>
<p>NFT marketplaces and Web3 wallet-connect flows. The rotating rainbow reads as blockchain / crypto premium and matches audience expectation.</p>
<p>Dev-tool marketing pages (Cursor, Warp, Zed, Raycast). The iridescent border reads as “this is a crafted product” without needing prose to say it.</p>
<p>AI/LLM product landing pages. The gradient signals novelty and generative aesthetics without leaning on the tired holographic-mesh cliché.</p>
<p>Gaming portals. Full RGB spin at 2s duration reads as gamer aesthetic instantly — the audience welcomes the energy.</p>
<h3>Where it doesn't belong</h3>
<p>Fintech dashboards for regulated audiences (banking, insurance). The animation reads as gimmicky and undermines the trust signal these products need.</p>
<p>Healthcare and public-sector sites. Same reasoning — the accessibility-first audience needs quiet chrome, not chasing lights.</p>
<p>Legal firm websites. ABA Model Rule 7.1 requires substantiated claims; a spinning iridescent border sends the wrong signal about seriousness.</p>
<p>Enterprise dashboards where the user spends 8 hours a day. The animation would be genuinely irritating over that duration. Reserve for marketing surfaces, not the product itself.</p>
<p>Keep scrolling — the sticky frame stays lit, stays glass, and demonstrates its behaviour across the full page height.</p>
</div>
</div>
</div><div class="tgn-08 w-full min-h-svh bg-tgn08-night bg-[radial-gradient(90%_120%_at_15%_0%,var(--color-tgn08-dusk),var(--color-tgn08-night)_70%)] font-tgn08-sans">
<div class="relative h-svh overflow-y-auto scroll-smooth px-4 py-5 sm:px-6 sm:py-7">
<header class="group/frame sticky top-0 z-10 rounded-2xl p-0.5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:p-0.5 before:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] before:[mask:linear-gradient(#000_0_0)_content-box_exclude,linear-gradient(#000_0_0)] before:animate-tgn08-spin after:pointer-events-none after:absolute after:inset-0 after:-z-10 after:rounded-[inherit] after:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] after:opacity-40 after:blur-xl after:animate-tgn08-spin after:transition-opacity after:duration-300 hover:after:opacity-75 focus-within:after:opacity-75 motion-reduce:before:animate-none motion-reduce:after:animate-none">
<div class="relative flex h-15 items-center gap-5 rounded-[14px] bg-tgn08-glass/60 px-5 backdrop-blur-lg backdrop-saturate-[1.6] not-supports-[backdrop-filter:blur(1px)]:bg-tgn08-glass max-sm:h-14 max-sm:gap-2 max-sm:px-3">
<a class="flex items-center gap-2 rounded-md text-lg font-bold tracking-[-0.02em] text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c" href="#"><span aria-hidden="true" class="size-4 rotate-45 rounded-[3px] bg-[conic-gradient(from_45deg,var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))]"></span>Prism</a>
<nav class="ml-auto" aria-label="Primary">
<ul class="flex gap-1 max-sm:gap-0">
<li><a href="#" aria-current="page" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Studio</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Gallery</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Shop</a></li>
<li class="max-[400px]:hidden"><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Info</a></li>
</ul>
</nav>
</div>
</header>
<div class="mx-auto max-w-2xl px-2 pt-12 pb-20 text-tgn08-ink/88 [&_p]:mb-3.5 [&_p]:text-[15px]/[1.65] [&_p]:font-medium [&_p]:text-pretty [&_:is(h1,h2,h3)]:text-balance [&_h2]:mt-5 [&_h2]:mb-3.5 [&_h2]:text-[22px]/[1.2] [&_h2]:font-extrabold [&_h2]:tracking-[-0.015em] [&_h3]:mt-8 [&_h3]:mb-3 [&_h3]:text-lg/[1.25] [&_h3]:font-bold [&_h3]:tracking-[-0.01em] [&_:is(h2,h3)]:text-white [&_code]:rounded-md [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-tgn08-mono [&_code]:text-[12.5px] [&_code]:font-medium [&_code]:border [&_code]:border-white/18 [&_code]:bg-white/10 [&_code]:text-white">
<h2>Watch the border chase § the frame stays lit while you scroll</h2>
<p>The sticky frame keeps its rotating gradient border visible the whole way down the page. Because <code>@property --angle</code> is registered as a typed <code><angle></code>, CSS can actually interpolate it — untyped custom properties snap between values.</p>
<p>A pseudo-element sits behind the bar, one <code>--border-width</code> larger on every side, filled with a <code>conic-gradient(from var(--angle), …)</code>. The gradient rotates through 360deg; the only visible slice is the thin frame peeking around the glass bar in front.</p>
<p>The gradient stops ARE the palette. Two or three saturated hues at a few positions read as a chasing highlight; a full oklch hue wheel reads as an iridescent ring.</p>
<h3>The @property gate</h3>
<p>Registered custom properties are the entire reason this animation works. Without <code>@property</code>, the browser treats <code>--angle</code> as a plain string and cannot interpolate it — the keyframe animation would snap from 0deg to 360deg with no intermediate frames.</p>
<p>The registration tells the browser: this variable is an <code><angle></code> type, has an initial value of 0deg, and does not inherit. Now CSS can smoothly tween it, and the conic-gradient re-renders continuously.</p>
<p>This is CSS Houdini territory — the ability to define new typed primitives. Baseline support arrived in 2024 (Firefox 128 was the last major engine). For older browsers, the border shows a static gradient at the initial angle — a graceful fallback that still looks intentional.</p>
<h3>Mask-composite is the second half of the trick</h3>
<p>The gradient pseudo-element fills the entire frame area, not just the border. To reveal only the border, use <code>mask-composite:exclude</code> with two masks: one for the outer edge, one for the inner content area. The subtraction leaves only the ring.</p>
<p>This is the same technique CSS Tricks documented for gradient borders. Combined with the rotating <code>--angle</code>, it creates the lit-edge illusion without any actual border property.</p>
<p>The alternative — a real <code>border-image</code> with an animated gradient — doesn't work because <code>border-image</code> cannot animate its gradient angle directly. The conic + mask + <code>@property</code> route is the only way in current CSS.</p>
<h3>Polish moves</h3>
<p>Add a <code>filter:blur(6px)</code> on the gradient pseudo-element to convert the crisp border into a soft glow halo. Or a matching <code>box-shadow</code> to bleed the colour outward for a bigger lit-edge feel.</p>
<p>Speed via the animation duration: 6s is an elegant drift, 2s is an energetic gamer-RGB spin. Freeze one segment as an accent by dropping the animation entirely for a static gradient border.</p>
<p>Animate <code>--angle</code> on hover only rather than continuously. The border comes alive when the user engages the nav and stays quiet otherwise — better for battery on mobile and less visually noisy on long-form content pages.</p>
<p>A constantly-spinning border repaints every frame — respect <code>prefers-reduced-motion</code> and consider pausing it when off-screen for battery.</p>
<h3>Where iridescent borders belong</h3>
<p>NFT marketplaces and Web3 wallet-connect flows. The rotating rainbow reads as blockchain / crypto premium and matches audience expectation.</p>
<p>Dev-tool marketing pages (Cursor, Warp, Zed, Raycast). The iridescent border reads as “this is a crafted product” without needing prose to say it.</p>
<p>AI/LLM product landing pages. The gradient signals novelty and generative aesthetics without leaning on the tired holographic-mesh cliché.</p>
<p>Gaming portals. Full RGB spin at 2s duration reads as gamer aesthetic instantly — the audience welcomes the energy.</p>
<h3>Where it doesn't belong</h3>
<p>Fintech dashboards for regulated audiences (banking, insurance). The animation reads as gimmicky and undermines the trust signal these products need.</p>
<p>Healthcare and public-sector sites. Same reasoning — the accessibility-first audience needs quiet chrome, not chasing lights.</p>
<p>Legal firm websites. ABA Model Rule 7.1 requires substantiated claims; a spinning iridescent border sends the wrong signal about seriousness.</p>
<p>Enterprise dashboards where the user spends 8 hours a day. The animation would be genuinely irritating over that duration. Reserve for marketing surfaces, not the product itself.</p>
<p>Keep scrolling — the sticky frame stays lit, stays glass, and demonstrates its behaviour across the full page height.</p>
</div>
</div>
</div>@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<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.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}<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..700&family=JetBrains+Mono:wght@400;500;600;700&display=swap">
<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..700&family=JetBrains+Mono:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
.gn-08-frame::beforebecamebefore:utilities including the mask as an arbitrary property; the--border-widthvariable becamep-0.5on both the frame and the ring.@keyframes gn08spinmoved into@themeas--animate-tgn08-spin, so it ships only because a utility uses it.- UI upgrade from the CSS original: the
filter:drop-shadowglow (which forced the whole ring to re-filter every frame) became a separate blurredafter:layer that also brightens on hover andfocus-within. - UI upgrade: a gradient logo mark ties the brand to the border, tap targets stay 44px on phones (were 36px at 11px type), and the fourth link drops below 400px instead of squeezing the type.
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 Animated Gradient Border Glass Navbar
Source: https://codefronts.com/navigation/tailwind-css-glassmorphic-sticky-navbars/tailwind-animated-gradient-border-glass-navbar/
An iridescent conic-gradient border chasing around a dark glass bar, with a soft blurred glow of the same gradient underneath. The angle is a registered @property (the one thing that must stay CSS), the spin is an @theme animation token, and the ring itself is a masked before: layer.
## HTML
```html
<div class="tgn-08 w-full min-h-svh bg-tgn08-night bg-[radial-gradient(90%_120%_at_15%_0%,var(--color-tgn08-dusk),var(--color-tgn08-night)_70%)] font-tgn08-sans">
<div class="relative h-svh overflow-y-auto scroll-smooth px-4 py-5 sm:px-6 sm:py-7">
<header class="group/frame sticky top-0 z-10 rounded-2xl p-0.5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:p-0.5 before:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] before:[mask:linear-gradient(#000_0_0)_content-box_exclude,linear-gradient(#000_0_0)] before:animate-tgn08-spin after:pointer-events-none after:absolute after:inset-0 after:-z-10 after:rounded-[inherit] after:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] after:opacity-40 after:blur-xl after:animate-tgn08-spin after:transition-opacity after:duration-300 hover:after:opacity-75 focus-within:after:opacity-75 motion-reduce:before:animate-none motion-reduce:after:animate-none">
<div class="relative flex h-15 items-center gap-5 rounded-[14px] bg-tgn08-glass/60 px-5 backdrop-blur-lg backdrop-saturate-[1.6] not-supports-[backdrop-filter:blur(1px)]:bg-tgn08-glass max-sm:h-14 max-sm:gap-2 max-sm:px-3">
<a class="flex items-center gap-2 rounded-md text-lg font-bold tracking-[-0.02em] text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c" href="#"><span aria-hidden="true" class="size-4 rotate-45 rounded-[3px] bg-[conic-gradient(from_45deg,var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))]"></span>Prism</a>
<nav class="ml-auto" aria-label="Primary">
<ul class="flex gap-1 max-sm:gap-0">
<li><a href="#" aria-current="page" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Studio</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Gallery</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Shop</a></li>
<li class="max-[400px]:hidden"><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Info</a></li>
</ul>
</nav>
</div>
</header>
<div class="mx-auto max-w-2xl px-2 pt-12 pb-20 text-tgn08-ink/88 [&_p]:mb-3.5 [&_p]:text-[15px]/[1.65] [&_p]:font-medium [&_p]:text-pretty [&_:is(h1,h2,h3)]:text-balance [&_h2]:mt-5 [&_h2]:mb-3.5 [&_h2]:text-[22px]/[1.2] [&_h2]:font-extrabold [&_h2]:tracking-[-0.015em] [&_h3]:mt-8 [&_h3]:mb-3 [&_h3]:text-lg/[1.25] [&_h3]:font-bold [&_h3]:tracking-[-0.01em] [&_:is(h2,h3)]:text-white [&_code]:rounded-md [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-tgn08-mono [&_code]:text-[12.5px] [&_code]:font-medium [&_code]:border [&_code]:border-white/18 [&_code]:bg-white/10 [&_code]:text-white">
<h2>Watch the border chase § the frame stays lit while you scroll</h2>
<p>The sticky frame keeps its rotating gradient border visible the whole way down the page. Because <code>@property --angle</code> is registered as a typed <code><angle></code>, CSS can actually interpolate it — untyped custom properties snap between values.</p>
<p>A pseudo-element sits behind the bar, one <code>--border-width</code> larger on every side, filled with a <code>conic-gradient(from var(--angle), …)</code>. The gradient rotates through 360deg; the only visible slice is the thin frame peeking around the glass bar in front.</p>
<p>The gradient stops ARE the palette. Two or three saturated hues at a few positions read as a chasing highlight; a full oklch hue wheel reads as an iridescent ring.</p>
<h3>The @property gate</h3>
<p>Registered custom properties are the entire reason this animation works. Without <code>@property</code>, the browser treats <code>--angle</code> as a plain string and cannot interpolate it — the keyframe animation would snap from 0deg to 360deg with no intermediate frames.</p>
<p>The registration tells the browser: this variable is an <code><angle></code> type, has an initial value of 0deg, and does not inherit. Now CSS can smoothly tween it, and the conic-gradient re-renders continuously.</p>
<p>This is CSS Houdini territory — the ability to define new typed primitives. Baseline support arrived in 2024 (Firefox 128 was the last major engine). For older browsers, the border shows a static gradient at the initial angle — a graceful fallback that still looks intentional.</p>
<h3>Mask-composite is the second half of the trick</h3>
<p>The gradient pseudo-element fills the entire frame area, not just the border. To reveal only the border, use <code>mask-composite:exclude</code> with two masks: one for the outer edge, one for the inner content area. The subtraction leaves only the ring.</p>
<p>This is the same technique CSS Tricks documented for gradient borders. Combined with the rotating <code>--angle</code>, it creates the lit-edge illusion without any actual border property.</p>
<p>The alternative — a real <code>border-image</code> with an animated gradient — doesn't work because <code>border-image</code> cannot animate its gradient angle directly. The conic + mask + <code>@property</code> route is the only way in current CSS.</p>
<h3>Polish moves</h3>
<p>Add a <code>filter:blur(6px)</code> on the gradient pseudo-element to convert the crisp border into a soft glow halo. Or a matching <code>box-shadow</code> to bleed the colour outward for a bigger lit-edge feel.</p>
<p>Speed via the animation duration: 6s is an elegant drift, 2s is an energetic gamer-RGB spin. Freeze one segment as an accent by dropping the animation entirely for a static gradient border.</p>
<p>Animate <code>--angle</code> on hover only rather than continuously. The border comes alive when the user engages the nav and stays quiet otherwise — better for battery on mobile and less visually noisy on long-form content pages.</p>
<p>A constantly-spinning border repaints every frame — respect <code>prefers-reduced-motion</code> and consider pausing it when off-screen for battery.</p>
<h3>Where iridescent borders belong</h3>
<p>NFT marketplaces and Web3 wallet-connect flows. The rotating rainbow reads as blockchain / crypto premium and matches audience expectation.</p>
<p>Dev-tool marketing pages (Cursor, Warp, Zed, Raycast). The iridescent border reads as “this is a crafted product” without needing prose to say it.</p>
<p>AI/LLM product landing pages. The gradient signals novelty and generative aesthetics without leaning on the tired holographic-mesh cliché.</p>
<p>Gaming portals. Full RGB spin at 2s duration reads as gamer aesthetic instantly — the audience welcomes the energy.</p>
<h3>Where it doesn't belong</h3>
<p>Fintech dashboards for regulated audiences (banking, insurance). The animation reads as gimmicky and undermines the trust signal these products need.</p>
<p>Healthcare and public-sector sites. Same reasoning — the accessibility-first audience needs quiet chrome, not chasing lights.</p>
<p>Legal firm websites. ABA Model Rule 7.1 requires substantiated claims; a spinning iridescent border sends the wrong signal about seriousness.</p>
<p>Enterprise dashboards where the user spends 8 hours a day. The animation would be genuinely irritating over that duration. Reserve for marketing surfaces, not the product itself.</p>
<p>Keep scrolling — the sticky frame stays lit, stays glass, and demonstrates its behaviour across the full page height.</p>
</div>
</div>
</div>
```
## CSS
```css
@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}
```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 Animated Gradient Border Glass Navbar
Source: https://codefronts.com/navigation/tailwind-css-glassmorphic-sticky-navbars/tailwind-animated-gradient-border-glass-navbar/
An iridescent conic-gradient border chasing around a dark glass bar, with a soft blurred glow of the same gradient underneath. The angle is a registered @property (the one thing that must stay CSS), the spin is an @theme animation token, and the ring itself is a masked before: layer.
## HTML
```html
<div class="tgn-08 w-full min-h-svh bg-tgn08-night bg-[radial-gradient(90%_120%_at_15%_0%,var(--color-tgn08-dusk),var(--color-tgn08-night)_70%)] font-tgn08-sans">
<div class="relative h-svh overflow-y-auto scroll-smooth px-4 py-5 sm:px-6 sm:py-7">
<header class="group/frame sticky top-0 z-10 rounded-2xl p-0.5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:p-0.5 before:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] before:[mask:linear-gradient(#000_0_0)_content-box_exclude,linear-gradient(#000_0_0)] before:animate-tgn08-spin after:pointer-events-none after:absolute after:inset-0 after:-z-10 after:rounded-[inherit] after:bg-[conic-gradient(from_var(--tgn08-angle),var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))] after:opacity-40 after:blur-xl after:animate-tgn08-spin after:transition-opacity after:duration-300 hover:after:opacity-75 focus-within:after:opacity-75 motion-reduce:before:animate-none motion-reduce:after:animate-none">
<div class="relative flex h-15 items-center gap-5 rounded-[14px] bg-tgn08-glass/60 px-5 backdrop-blur-lg backdrop-saturate-[1.6] not-supports-[backdrop-filter:blur(1px)]:bg-tgn08-glass max-sm:h-14 max-sm:gap-2 max-sm:px-3">
<a class="flex items-center gap-2 rounded-md text-lg font-bold tracking-[-0.02em] text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c" href="#"><span aria-hidden="true" class="size-4 rotate-45 rounded-[3px] bg-[conic-gradient(from_45deg,var(--color-tgn08-a),var(--color-tgn08-b),var(--color-tgn08-c),var(--color-tgn08-d),var(--color-tgn08-a))]"></span>Prism</a>
<nav class="ml-auto" aria-label="Primary">
<ul class="flex gap-1 max-sm:gap-0">
<li><a href="#" aria-current="page" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Studio</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Gallery</a></li>
<li><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Shop</a></li>
<li class="max-[400px]:hidden"><a href="#" class="flex h-11 items-center rounded-[10px] px-3.5 text-sm font-medium text-tgn08-ink/80 transition-colors hover:bg-white/10 hover:text-white aria-[current=page]:bg-white/14 aria-[current=page]:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tgn08-c max-sm:px-2.5 max-sm:text-[13px]">Info</a></li>
</ul>
</nav>
</div>
</header>
<div class="mx-auto max-w-2xl px-2 pt-12 pb-20 text-tgn08-ink/88 [&_p]:mb-3.5 [&_p]:text-[15px]/[1.65] [&_p]:font-medium [&_p]:text-pretty [&_:is(h1,h2,h3)]:text-balance [&_h2]:mt-5 [&_h2]:mb-3.5 [&_h2]:text-[22px]/[1.2] [&_h2]:font-extrabold [&_h2]:tracking-[-0.015em] [&_h3]:mt-8 [&_h3]:mb-3 [&_h3]:text-lg/[1.25] [&_h3]:font-bold [&_h3]:tracking-[-0.01em] [&_:is(h2,h3)]:text-white [&_code]:rounded-md [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-tgn08-mono [&_code]:text-[12.5px] [&_code]:font-medium [&_code]:border [&_code]:border-white/18 [&_code]:bg-white/10 [&_code]:text-white">
<h2>Watch the border chase § the frame stays lit while you scroll</h2>
<p>The sticky frame keeps its rotating gradient border visible the whole way down the page. Because <code>@property --angle</code> is registered as a typed <code><angle></code>, CSS can actually interpolate it — untyped custom properties snap between values.</p>
<p>A pseudo-element sits behind the bar, one <code>--border-width</code> larger on every side, filled with a <code>conic-gradient(from var(--angle), …)</code>. The gradient rotates through 360deg; the only visible slice is the thin frame peeking around the glass bar in front.</p>
<p>The gradient stops ARE the palette. Two or three saturated hues at a few positions read as a chasing highlight; a full oklch hue wheel reads as an iridescent ring.</p>
<h3>The @property gate</h3>
<p>Registered custom properties are the entire reason this animation works. Without <code>@property</code>, the browser treats <code>--angle</code> as a plain string and cannot interpolate it — the keyframe animation would snap from 0deg to 360deg with no intermediate frames.</p>
<p>The registration tells the browser: this variable is an <code><angle></code> type, has an initial value of 0deg, and does not inherit. Now CSS can smoothly tween it, and the conic-gradient re-renders continuously.</p>
<p>This is CSS Houdini territory — the ability to define new typed primitives. Baseline support arrived in 2024 (Firefox 128 was the last major engine). For older browsers, the border shows a static gradient at the initial angle — a graceful fallback that still looks intentional.</p>
<h3>Mask-composite is the second half of the trick</h3>
<p>The gradient pseudo-element fills the entire frame area, not just the border. To reveal only the border, use <code>mask-composite:exclude</code> with two masks: one for the outer edge, one for the inner content area. The subtraction leaves only the ring.</p>
<p>This is the same technique CSS Tricks documented for gradient borders. Combined with the rotating <code>--angle</code>, it creates the lit-edge illusion without any actual border property.</p>
<p>The alternative — a real <code>border-image</code> with an animated gradient — doesn't work because <code>border-image</code> cannot animate its gradient angle directly. The conic + mask + <code>@property</code> route is the only way in current CSS.</p>
<h3>Polish moves</h3>
<p>Add a <code>filter:blur(6px)</code> on the gradient pseudo-element to convert the crisp border into a soft glow halo. Or a matching <code>box-shadow</code> to bleed the colour outward for a bigger lit-edge feel.</p>
<p>Speed via the animation duration: 6s is an elegant drift, 2s is an energetic gamer-RGB spin. Freeze one segment as an accent by dropping the animation entirely for a static gradient border.</p>
<p>Animate <code>--angle</code> on hover only rather than continuously. The border comes alive when the user engages the nav and stays quiet otherwise — better for battery on mobile and less visually noisy on long-form content pages.</p>
<p>A constantly-spinning border repaints every frame — respect <code>prefers-reduced-motion</code> and consider pausing it when off-screen for battery.</p>
<h3>Where iridescent borders belong</h3>
<p>NFT marketplaces and Web3 wallet-connect flows. The rotating rainbow reads as blockchain / crypto premium and matches audience expectation.</p>
<p>Dev-tool marketing pages (Cursor, Warp, Zed, Raycast). The iridescent border reads as “this is a crafted product” without needing prose to say it.</p>
<p>AI/LLM product landing pages. The gradient signals novelty and generative aesthetics without leaning on the tired holographic-mesh cliché.</p>
<p>Gaming portals. Full RGB spin at 2s duration reads as gamer aesthetic instantly — the audience welcomes the energy.</p>
<h3>Where it doesn't belong</h3>
<p>Fintech dashboards for regulated audiences (banking, insurance). The animation reads as gimmicky and undermines the trust signal these products need.</p>
<p>Healthcare and public-sector sites. Same reasoning — the accessibility-first audience needs quiet chrome, not chasing lights.</p>
<p>Legal firm websites. ABA Model Rule 7.1 requires substantiated claims; a spinning iridescent border sends the wrong signal about seriousness.</p>
<p>Enterprise dashboards where the user spends 8 hours a day. The animation would be genuinely irritating over that duration. Reserve for marketing surfaces, not the product itself.</p>
<p>Keep scrolling — the sticky frame stays lit, stays glass, and demonstrates its behaviour across the full page height.</p>
</div>
</div>
</div>
```
## CSS
```css
@import "tailwindcss";
/* @property is an at-rule with no utility equivalent — the one piece of real CSS here. */
@property --tgn08-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@theme {
--color-tgn08-a: #ff725c;
--color-tgn08-a: oklch(0.75 0.2 30);
--color-tgn08-b: #e181f7;
--color-tgn08-b: oklch(0.75 0.19 320);
--color-tgn08-c: #5ebdff;
--color-tgn08-c: oklch(0.78 0.16 250);
--color-tgn08-d: #21e79b;
--color-tgn08-d: oklch(0.82 0.18 160);
--color-tgn08-dusk: #2b1e66;
--color-tgn08-dusk: oklch(0.3 0.12 285);
--color-tgn08-night: #030a26;
--color-tgn08-night: oklch(0.16 0.06 265);
--color-tgn08-glass: #100d26;
--color-tgn08-glass: oklch(0.18 0.05 285);
--color-tgn08-ink: #f1f1f8;
--color-tgn08-ink: oklch(0.96 0.01 285);
--font-tgn08-sans: 'Space Grotesk', system-ui, sans-serif;
--font-tgn08-mono: 'JetBrains Mono', ui-monospace, monospace;
--animate-tgn08-spin: tgn08spin 6s linear infinite;
@keyframes tgn08spin {
to {
--tgn08-angle: 360deg;
}
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tgn-08 {
width: 100%;
min-height: 100svh;
}
```How this works
Register the angle. An unregistered custom property interpolates as a string, so it jumps; registering it as <angle> lets @keyframes tween it:
@property --tgn08-angle { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
--animate-tgn08-spin: tgn08spin 6s linear infinite;Mask out the middle. The before: layer is the full conic gradient with p-0.5; the two-layer mask with exclude subtracts its content box, leaving only the padding ring.
Glow layer. after: repeats the gradient at -z-10, blurred and at 40% opacity, so the light seems to spill from the border onto the page.
Make it yours
- Speed: change
6sin--animate-tgn08-spin; 3s feels gaming, 10s feels calm. - Two-tone: reduce the conic stops to
tgn08-aandtgn08-cfor a brand-coloured chase. - Thicker ring:
p-[3px]on the header andbefore:p-[3px]together.
Gotchas — read before shipping
- The ring and the frame padding must match (
p-0.5/before:p-0.5) or the bar won't sit flush inside the border. - A constantly spinning border repaints every frame; it stops under
motion-reduce:. - Without
@propertysupport the border shows a static gradient — a correct fallback, not a bug.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
@property is Baseline 2024 (Firefox 128); mask-composite unprefixed since Safari 15.4. Floor matches Tailwind v4.