39 CSS Breadcrumbs19 / 39

Pure CSSMIT licensed

SaaS Marketing Site Gradient Text Breadcrumb Bar

The breadcrumb SaaS marketing sites like Linear and Vercel reach for when a single line of text needs to feel alive. Crumbs are painted with a slow-drifting conic gradient clipped to text via @property, so the hue cycles through vivid oklch stops without ever touching the layout.

Published

Live Demo
Try it

The code

<section class="bc-19" aria-label="SaaS marketing site gradient text breadcrumb demo">
      <nav aria-label="Breadcrumb">
        <ol class="bc-19__list">
          <li class="bc-19__item"><a class="bc-19__link" href="#">Docs</a></li>
          <li class="bc-19__item"><a class="bc-19__link" href="#">Guides</a></li>
          <li class="bc-19__item"><a class="bc-19__link" href="#">Authentication</a></li>
          <li class="bc-19__item"><a class="bc-19__link" aria-current="page" href="#">Magic Links</a></li>
        </ol>
      </nav>
    </section>
@property --grad-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.bc-19 {
  width: 100%;
  min-height: 100vh;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 6vw, 64px) clamp(16px, 5vw, 48px);
  font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  background: radial-gradient(1200px 600px at 50% -10%, oklch(0.96 0.02 270 / 0.9), transparent 60%), linear-gradient(180deg, oklch(0.99 0.005 260), oklch(0.97 0.01 265));
  color: oklch(0.28 0.02 260);
  -webkit-font-smoothing: antialiased;
}

.bc-19 nav {
  width: 100%;
  max-width: 880px;
  padding: 14px 22px;
  border-radius: 14px;
  background: oklch(1 0 0 / 0.72);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border: 1px solid oklch(0.9 0.01 260 / 0.7);
  box-shadow: 0 1px 0 oklch(1 0 0 / 0.9) inset, 0 12px 40px -18px oklch(0.3 0.05 270 / 0.35);
}

.bc-19__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 4px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: clamp(14px, 1.6vw, 16px);
  font-weight: 500;
  letter-spacing: -0.005em;
}

.bc-19__item {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.bc-19__item + .bc-19__item::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 10px;
  border-right: 1.5px solid oklch(0.75 0.02 260);
  border-bottom: 1.5px solid oklch(0.75 0.02 260);
  transform: rotate(-45deg);
  opacity: 0.7;
}

.bc-19__link {
  --grad-stops: oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.72 0.2 25), oklch(0.7 0.2 190), oklch(0.62 0.2 285);
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 6px 8px;
  border-radius: 8px;
  text-decoration: none;
  color: oklch(0.42 0.03 265);
  background: conic-gradient(from var(--grad-angle), var(--grad-stops));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: bc31-drift 18s linear infinite;
  transition: transform 0.25s ease, filter 0.25s ease;
}

.bc-19__link::after {
  content: '';
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 4px;
  height: 1.5px;
  border-radius: 2px;
  background: conic-gradient(from var(--grad-angle), var(--grad-stops));
  opacity: 0;
  transform: scaleX(0.4);
  transform-origin: left center;
  transition: opacity 0.25s ease, transform 0.35s ease;
}

.bc-19__link:hover,
.bc-19__link:focus-visible {
  animation-duration: 6s;
  filter: saturate(1.15);
}

.bc-19__link:hover::after,
.bc-19__link:focus-visible::after {
  opacity: 0.85;
  transform: scaleX(1);
}

.bc-19__link:focus-visible {
  outline: 2px solid oklch(0.62 0.2 285);
  outline-offset: 3px;
}

.bc-19__link[aria-current='page'] {
  --grad-stops: oklch(0.6 0.24 300), oklch(0.68 0.24 340), oklch(0.72 0.22 20), oklch(0.66 0.24 275), oklch(0.6 0.24 300);
  font-weight: 650;
  animation-duration: 7s;
}

@keyframes bc31-drift {
  to {
    --grad-angle: 360deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bc-19__link,
    .bc-19__link[aria-current='page'] {
    animation: none;
    background: linear-gradient(90deg, oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.66 0.24 20));
    -webkit-background-clip: text;
    background-clip: text;
  }

  .bc-19__link::after {
    transition: none;
  }
}

@supports not (background: paint(something)) {
  /* Older engines without @property still get a static clipped gradient. */

  .bc-19__link {
    background: linear-gradient(90deg, oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.66 0.24 20));
    -webkit-background-clip: text;
    background-clip: text;
    animation: none;
  }
}
/* No JavaScript — @property + conic-gradient + background-clip:text drives the animated gradient text. */
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 Breadcrumb 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: SaaS Marketing Site Gradient Text Breadcrumb Bar
Source: https://codefronts.com/navigation/css-breadcrumbs/gradient-text/

The breadcrumb SaaS marketing sites like Linear and Vercel reach for when a single line of text needs to feel alive. Crumbs are painted with a slow-drifting conic gradient clipped to text via @property, so the hue cycles through vivid oklch stops without ever touching the layout.
## HTML
```html
<section class="bc-19" aria-label="SaaS marketing site gradient text breadcrumb demo">
      <nav aria-label="Breadcrumb">
        <ol class="bc-19__list">
          <li class="bc-19__item"><a class="bc-19__link" href="#">Docs</a></li>
          <li class="bc-19__item"><a class="bc-19__link" href="#">Guides</a></li>
          <li class="bc-19__item"><a class="bc-19__link" href="#">Authentication</a></li>
          <li class="bc-19__item"><a class="bc-19__link" aria-current="page" href="#">Magic Links</a></li>
        </ol>
      </nav>
    </section>
```
## CSS
```css
@property --grad-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.bc-19 {
  width: 100%;
  min-height: 100vh;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 6vw, 64px) clamp(16px, 5vw, 48px);
  font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  background: radial-gradient(1200px 600px at 50% -10%, oklch(0.96 0.02 270 / 0.9), transparent 60%), linear-gradient(180deg, oklch(0.99 0.005 260), oklch(0.97 0.01 265));
  color: oklch(0.28 0.02 260);
  -webkit-font-smoothing: antialiased;
}

.bc-19 nav {
  width: 100%;
  max-width: 880px;
  padding: 14px 22px;
  border-radius: 14px;
  background: oklch(1 0 0 / 0.72);
  backdrop-filter: blur(14px) saturate(1.1);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border: 1px solid oklch(0.9 0.01 260 / 0.7);
  box-shadow: 0 1px 0 oklch(1 0 0 / 0.9) inset, 0 12px 40px -18px oklch(0.3 0.05 270 / 0.35);
}

.bc-19__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 4px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: clamp(14px, 1.6vw, 16px);
  font-weight: 500;
  letter-spacing: -0.005em;
}

.bc-19__item {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.bc-19__item + .bc-19__item::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 10px;
  border-right: 1.5px solid oklch(0.75 0.02 260);
  border-bottom: 1.5px solid oklch(0.75 0.02 260);
  transform: rotate(-45deg);
  opacity: 0.7;
}

.bc-19__link {
  --grad-stops: oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.72 0.2 25), oklch(0.7 0.2 190), oklch(0.62 0.2 285);
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 6px 8px;
  border-radius: 8px;
  text-decoration: none;
  color: oklch(0.42 0.03 265);
  background: conic-gradient(from var(--grad-angle), var(--grad-stops));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: bc31-drift 18s linear infinite;
  transition: transform 0.25s ease, filter 0.25s ease;
}

.bc-19__link::after {
  content: '';
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 4px;
  height: 1.5px;
  border-radius: 2px;
  background: conic-gradient(from var(--grad-angle), var(--grad-stops));
  opacity: 0;
  transform: scaleX(0.4);
  transform-origin: left center;
  transition: opacity 0.25s ease, transform 0.35s ease;
}

.bc-19__link:hover,
.bc-19__link:focus-visible {
  animation-duration: 6s;
  filter: saturate(1.15);
}

.bc-19__link:hover::after,
.bc-19__link:focus-visible::after {
  opacity: 0.85;
  transform: scaleX(1);
}

.bc-19__link:focus-visible {
  outline: 2px solid oklch(0.62 0.2 285);
  outline-offset: 3px;
}

.bc-19__link[aria-current='page'] {
  --grad-stops: oklch(0.6 0.24 300), oklch(0.68 0.24 340), oklch(0.72 0.22 20), oklch(0.66 0.24 275), oklch(0.6 0.24 300);
  font-weight: 650;
  animation-duration: 7s;
}

@keyframes bc31-drift {
  to {
    --grad-angle: 360deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bc-19__link,
    .bc-19__link[aria-current='page'] {
    animation: none;
    background: linear-gradient(90deg, oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.66 0.24 20));
    -webkit-background-clip: text;
    background-clip: text;
  }

  .bc-19__link::after {
    transition: none;
  }
}

@supports not (background: paint(something)) {
  /* Older engines without @property still get a static clipped gradient. */

  .bc-19__link {
    background: linear-gradient(90deg, oklch(0.62 0.2 285), oklch(0.68 0.22 320), oklch(0.66 0.24 20));
    -webkit-background-clip: text;
    background-clip: text;
    animation: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — @property + conic-gradient + background-clip:text drives the animated gradient text. */
```

How this works

The star technique is a registered CSS custom property. @property --grad-angle declares the value as an <angle>, which lets the browser interpolate it smoothly across a @keyframes loop instead of snapping between string values. That angle drives a conic-gradient() built from wide-gamut oklch() stops, then background-clip: text plus the -webkit-background-clip: text prefix mask the paint to each crumb glyph. The current crumb uses a faster keyframe cycle and a punchier stop list so it reads as the visual anchor.

Semantics stay conventional: a <nav aria-label="Breadcrumb"> wraps an <ol>, the final crumb carries aria-current="page", and chevron separators are injected via ::before with aria-hidden implicitly handled since they never enter the accessibility tree. Every link gets a 44px minimum hit target, a :focus-visible ring that survives on any background, and the whole animation is silenced under prefers-reduced-motion.

Make it yours

  • Retune the palette by swapping the oklch() stops inside --grad-stops — keep chroma near 0.2 for that vivid marketing-site glow.
  • Slow or speed the drift by changing the 18s duration on @keyframes bc31-drift; the current crumb runs a faster 7s loop.
  • Swap chevrons for slashes or dots by editing the content value on .bc-19__item + .bc-19__item::before.
  • Force a dark editorial bar by toggling color-scheme: dark on .bc-19 — the gradient stops already read well on both surfaces.

Gotchas — read before shipping

  • Without @property support the angle jumps between keyframes instead of interpolating. Ship a static background fallback outside the @property block so pre-Firefox-128 users see a fixed gradient.
  • The -webkit-background-clip: text prefix is still required alongside the unprefixed rule in Safari and Chromium — omitting either one paints the background rectangle instead of clipping to glyphs.
  • Pair -webkit-text-fill-color: transparent with a real color declaration; if the background fails to load or clip, that color is what selection highlights and screen-reader mirrors will use.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Floor set by oklch(), backdrop-filter, @property as this demo is written. The core technique itself goes back further — Chrome 85+.

@property is the gate. Fallback: solid crumb color from a static rule outside the @property block.

Techniques used in this demo

Search CodeFronts

Loading…