39 CSS Breadcrumbs28 / 39

Pure CSSMIT licensed

Pure CSS Ribbon-Style Chevron Breadcrumb Trail

A bold ribbon-banner breadcrumb: overlapping coloured segments with folded-ribbon notches at each join, built from rotated pseudo-elements and layered fills — the tactile, physical 'paper ribbon' look for playful product and marketing UIs, done entirely in CSS.

Published Updated

Live Demo
Try it

The code

<nav class="bc-28" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Home</a></li>
    <li><a href="#">Shop</a></li>
    <li><a href="#">Toys</a></li>
    <li><a href="#" aria-current="page">Building Blocks</a></li>
  </ol>
</nav>
.bc-28 {
  width: 100%;
  min-height: 100vh;
  --d: 18px;
  font-family: system-ui,'Segoe UI',sans-serif;
  padding: 30px;
  background: oklch(0.96 0.02 60);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bc-28 * {
  box-sizing: border-box;
}

.bc-28 ol {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

.bc-28 li {
  display: flex;
  position: relative;
}

.bc-28 li:nth-child(1) {
  z-index: 4;
}

.bc-28 li:nth-child(2) {
  z-index: 3;
}

.bc-28 li:nth-child(3) {
  z-index: 2;
}

.bc-28 li:nth-child(4) {
  z-index: 1;
}

.bc-28 a {
  display: flex;
  align-items: center;
  height: 42px;
  padding: 0 20px 0 30px;
  margin-inline-start: calc(var(--d) * -1);
  font: 700 13.5px/1 system-ui,sans-serif;
  color: #fff;
  text-decoration: none;
  background: oklch(0.68 0.17 40);
  clip-path: polygon(0 0,calc(100% - var(--d)) 0,100% 50%,calc(100% - var(--d)) 100%,0 100%,var(--d) 50%);
  box-shadow: inset 14px 0 14px -12px rgba(0,0,0,.35);
  transition: filter .18s ease;
}

.bc-28 li:nth-child(2) a {
  background: oklch(0.7 0.16 25);
}

.bc-28 li:nth-child(3) a {
  background: oklch(0.72 0.15 15);
}

.bc-28 li:first-child a {
  margin-inline-start: 0;
  padding-left: 22px;
  clip-path: polygon(0 0,calc(100% - var(--d)) 0,100% 50%,calc(100% - var(--d)) 100%,0 100%);
}

.bc-28 li:last-child a {
  padding-right: 24px;
  background: oklch(0.66 0.19 350);
  clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--d) 50%);
}

.bc-28 a:hover {
  filter: brightness(1.08);
}

.bc-28 a:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2.5px #fff;
}

@media (prefers-reduced-motion: reduce) {
  .bc-28 a {
    transition: none;
  }
}
/* No JavaScript — overlapping clip-path chevron segments with an inset fold-shadow and ascending z-index read as a continuous folded ribbon. */
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: Pure CSS Ribbon-Style Chevron Breadcrumb Trail
Source: https://codefronts.com/navigation/css-breadcrumbs/subway-line/

A bold ribbon-banner breadcrumb: overlapping coloured segments with folded-ribbon notches at each join, built from rotated pseudo-elements and layered fills — the tactile, physical 'paper ribbon' look for playful product and marketing UIs, done entirely in CSS.
## HTML
```html
<nav class="bc-28" aria-label="Breadcrumb">
  <ol>
    <li><a href="#">Home</a></li>
    <li><a href="#">Shop</a></li>
    <li><a href="#">Toys</a></li>
    <li><a href="#" aria-current="page">Building Blocks</a></li>
  </ol>
</nav>
```
## CSS
```css
.bc-28 {
  width: 100%;
  min-height: 100vh;
  --d: 18px;
  font-family: system-ui,'Segoe UI',sans-serif;
  padding: 30px;
  background: oklch(0.96 0.02 60);
  display: flex;
  align-items: center;
  justify-content: center;
}

.bc-28 * {
  box-sizing: border-box;
}

.bc-28 ol {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

.bc-28 li {
  display: flex;
  position: relative;
}

.bc-28 li:nth-child(1) {
  z-index: 4;
}

.bc-28 li:nth-child(2) {
  z-index: 3;
}

.bc-28 li:nth-child(3) {
  z-index: 2;
}

.bc-28 li:nth-child(4) {
  z-index: 1;
}

.bc-28 a {
  display: flex;
  align-items: center;
  height: 42px;
  padding: 0 20px 0 30px;
  margin-inline-start: calc(var(--d) * -1);
  font: 700 13.5px/1 system-ui,sans-serif;
  color: #fff;
  text-decoration: none;
  background: oklch(0.68 0.17 40);
  clip-path: polygon(0 0,calc(100% - var(--d)) 0,100% 50%,calc(100% - var(--d)) 100%,0 100%,var(--d) 50%);
  box-shadow: inset 14px 0 14px -12px rgba(0,0,0,.35);
  transition: filter .18s ease;
}

.bc-28 li:nth-child(2) a {
  background: oklch(0.7 0.16 25);
}

.bc-28 li:nth-child(3) a {
  background: oklch(0.72 0.15 15);
}

.bc-28 li:first-child a {
  margin-inline-start: 0;
  padding-left: 22px;
  clip-path: polygon(0 0,calc(100% - var(--d)) 0,100% 50%,calc(100% - var(--d)) 100%,0 100%);
}

.bc-28 li:last-child a {
  padding-right: 24px;
  background: oklch(0.66 0.19 350);
  clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--d) 50%);
}

.bc-28 a:hover {
  filter: brightness(1.08);
}

.bc-28 a:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2.5px #fff;
}

@media (prefers-reduced-motion: reduce) {
  .bc-28 a {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — overlapping clip-path chevron segments with an inset fold-shadow and ascending z-index read as a continuous folded ribbon. */
```

How this works

Each crumb is a coloured segment whose right end forms a chevron point and whose left end bites an inward notch, so segments nest like a folded paper ribbon. The point + notch are cut with clip-path:polygon() (same family as demo 01) but here the fills step through a warm ribbon palette and a subtle inner box-shadow darkens each notch, selling the 'fold' where one ribbon tucks behind the next. A tiny ::before triangle in a darker shade sits at each join as the shadowed underside of the fold.

Because the segments overlap (negative inline margin) and ascend in z-index, the trail reads as a continuous physical ribbon rather than separate buttons. The current crumb takes the brightest fill and a soft lift. It's decorative-forward but stays honest: separators aren't in the text, links keep an inset focus ring (clip-path would slice an outline), and the palette meets contrast on white text.

Make it yours

  • Ribbon palette is a short list of oklch fills stepping in lightness/hue — reorder or recolour for brand.
  • Fold depth = the polygon's notch inset; deeper notches read as thicker ribbon.
  • Add a faint paper texture with a subtle repeating linear-gradient overlay at low opacity.
  • Round the whole bar's outer corners by clipping only the first/last segment's outer edge.

Gotchas — read before shipping

  • clip-path clips the focus outline — use an inset box-shadow ring for :focus-visible.
  • Overlap order matters: set ascending z-index so each segment's point sits above the next segment's notch.
  • Keep white text on mid-tone fills only — pale ribbon colours drop below contrast; test each palette step.
  • The fold-shadow triangle must be pointer-events:none so it doesn't block clicks on the link beneath.

Browser support

ChromeSafariFirefoxEdge
111+15.4+113+111+

Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome 55+.

clip-path + pseudo-elements are long-universal; oklch() palette (2023) is the only modern piece and swaps to hsl() trivially.

Techniques used in this demo

Search CodeFronts

Loading…