39 CSS Breadcrumbs13 / 39
Seamless Arrow-Cutout CSS3 Breadcrumb Trail
The interlocking-chevron breadcrumb built the classic CSS3 way — with ::before/::after triangles made from transparent-border tricks rather than clip-path. Each crumb's arrow is two rotated border-triangles that seamlessly notch into the next, the technique taught in every 'CSS arrow' tutorial, modernised.
Published
The code
<nav class="bc-13" aria-label="Breadcrumb">
<ol class="bc-13__list">
<li class="bc-13__item"><a class="bc-13__link" href="#">Home</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Catalog</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Tools</a></li>
<li class="bc-13__item"><a class="bc-13__link" aria-current="page" href="#">Power Drills</a></li>
</ol>
</nav><nav class="bc-13" aria-label="Breadcrumb">
<ol class="bc-13__list">
<li class="bc-13__item"><a class="bc-13__link" href="#">Home</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Catalog</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Tools</a></li>
<li class="bc-13__item"><a class="bc-13__link" aria-current="page" href="#">Power Drills</a></li>
</ol>
</nav>.bc-13 {
width: 100%;
min-height: 100vh;
--h: 44px;
--depth: 14px;
--page: oklch(0.96 0.01 90);
font-family: system-ui,'Segoe UI',sans-serif;
padding: 30px;
background: var(--page);
display: flex;
align-items: center;
justify-content: center;
}
.bc-13 * {
box-sizing: border-box;
}
.bc-13__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.bc-13__item {
display: flex;
position: relative;
}
.bc-13__item + .bc-13__item {
margin-inline-start: calc(var(--depth) * -1);
}
.bc-13__link {
position: relative;
display: flex;
align-items: center;
height: var(--h);
padding: 0 calc(var(--depth) + 12px) 0 calc(var(--depth) + 12px);
font: 600 13px/1 system-ui,sans-serif;
color: #fff;
text-decoration: none;
background: oklch(0.58 0.03 90);
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%,var(--depth) 50%);
transition: filter .18s ease;
}
.bc-13__item:first-child .bc-13__link {
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%);
padding-left: 16px;
}
.bc-13__item:last-child .bc-13__link {
clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--depth) 50%);
padding-right: 16px;
background: oklch(0.6 0.18 25);
}
.bc-13__item:first-child:last-child .bc-13__link {
clip-path: none;
}
.bc-13__item:nth-child(2) .bc-13__link {
background: oklch(0.52 0.05 60);
}
.bc-13__item:nth-child(3) .bc-13__link {
background: oklch(0.5 0.07 40);
}
.bc-13__link:hover {
filter: brightness(1.12);
}
.bc-13__link:focus-visible {
outline: 3px solid oklch(0.3 0.05 40);
outline-offset: 4px;
}
@media (prefers-reduced-motion: reduce) {
.bc-13__link {
transition: none;
}
}.bc-13 {
width: 100%;
min-height: 100vh;
--h: 44px;
--depth: 14px;
--page: oklch(0.96 0.01 90);
font-family: system-ui,'Segoe UI',sans-serif;
padding: 30px;
background: var(--page);
display: flex;
align-items: center;
justify-content: center;
}
.bc-13 * {
box-sizing: border-box;
}
.bc-13__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.bc-13__item {
display: flex;
position: relative;
}
.bc-13__item + .bc-13__item {
margin-inline-start: calc(var(--depth) * -1);
}
.bc-13__link {
position: relative;
display: flex;
align-items: center;
height: var(--h);
padding: 0 calc(var(--depth) + 12px) 0 calc(var(--depth) + 12px);
font: 600 13px/1 system-ui,sans-serif;
color: #fff;
text-decoration: none;
background: oklch(0.58 0.03 90);
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%,var(--depth) 50%);
transition: filter .18s ease;
}
.bc-13__item:first-child .bc-13__link {
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%);
padding-left: 16px;
}
.bc-13__item:last-child .bc-13__link {
clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--depth) 50%);
padding-right: 16px;
background: oklch(0.6 0.18 25);
}
.bc-13__item:first-child:last-child .bc-13__link {
clip-path: none;
}
.bc-13__item:nth-child(2) .bc-13__link {
background: oklch(0.52 0.05 60);
}
.bc-13__item:nth-child(3) .bc-13__link {
background: oklch(0.5 0.07 40);
}
.bc-13__link:hover {
filter: brightness(1.12);
}
.bc-13__link:focus-visible {
outline: 3px solid oklch(0.3 0.05 40);
outline-offset: 4px;
}
@media (prefers-reduced-motion: reduce) {
.bc-13__link {
transition: none;
}
}/* No JavaScript — arrows are transparent-border triangles (::after in the crumb colour, ::before in the page colour) that notch together seamlessly; the widest-support arrow technique. */
/* No JavaScript — arrows are transparent-border triangles (::after in the crumb colour, ::before in the page colour) that notch together seamlessly; the widest-support arrow technique. */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: Seamless Arrow-Cutout CSS3 Breadcrumb Trail
Source: https://codefronts.com/navigation/css-breadcrumbs/seamless-arrow-cutout-css3-breadcrumb-trail/
The interlocking-chevron breadcrumb built the classic CSS3 way — with ::before/::after triangles made from transparent-border tricks rather than clip-path. Each crumb's arrow is two rotated border-triangles that seamlessly notch into the next, the technique taught in every 'CSS arrow' tutorial, modernised.
## HTML
```html
<nav class="bc-13" aria-label="Breadcrumb">
<ol class="bc-13__list">
<li class="bc-13__item"><a class="bc-13__link" href="#">Home</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Catalog</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Tools</a></li>
<li class="bc-13__item"><a class="bc-13__link" aria-current="page" href="#">Power Drills</a></li>
</ol>
</nav>
```
## CSS
```css
.bc-13 {
width: 100%;
min-height: 100vh;
--h: 44px;
--depth: 14px;
--page: oklch(0.96 0.01 90);
font-family: system-ui,'Segoe UI',sans-serif;
padding: 30px;
background: var(--page);
display: flex;
align-items: center;
justify-content: center;
}
.bc-13 * {
box-sizing: border-box;
}
.bc-13__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.bc-13__item {
display: flex;
position: relative;
}
.bc-13__item + .bc-13__item {
margin-inline-start: calc(var(--depth) * -1);
}
.bc-13__link {
position: relative;
display: flex;
align-items: center;
height: var(--h);
padding: 0 calc(var(--depth) + 12px) 0 calc(var(--depth) + 12px);
font: 600 13px/1 system-ui,sans-serif;
color: #fff;
text-decoration: none;
background: oklch(0.58 0.03 90);
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%,var(--depth) 50%);
transition: filter .18s ease;
}
.bc-13__item:first-child .bc-13__link {
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%);
padding-left: 16px;
}
.bc-13__item:last-child .bc-13__link {
clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--depth) 50%);
padding-right: 16px;
background: oklch(0.6 0.18 25);
}
.bc-13__item:first-child:last-child .bc-13__link {
clip-path: none;
}
.bc-13__item:nth-child(2) .bc-13__link {
background: oklch(0.52 0.05 60);
}
.bc-13__item:nth-child(3) .bc-13__link {
background: oklch(0.5 0.07 40);
}
.bc-13__link:hover {
filter: brightness(1.12);
}
.bc-13__link:focus-visible {
outline: 3px solid oklch(0.3 0.05 40);
outline-offset: 4px;
}
@media (prefers-reduced-motion: reduce) {
.bc-13__link {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — arrows are transparent-border triangles (::after in the crumb colour, ::before in the page colour) that notch together seamlessly; the widest-support arrow technique. */
```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: Seamless Arrow-Cutout CSS3 Breadcrumb Trail
Source: https://codefronts.com/navigation/css-breadcrumbs/seamless-arrow-cutout-css3-breadcrumb-trail/
The interlocking-chevron breadcrumb built the classic CSS3 way — with ::before/::after triangles made from transparent-border tricks rather than clip-path. Each crumb's arrow is two rotated border-triangles that seamlessly notch into the next, the technique taught in every 'CSS arrow' tutorial, modernised.
## HTML
```html
<nav class="bc-13" aria-label="Breadcrumb">
<ol class="bc-13__list">
<li class="bc-13__item"><a class="bc-13__link" href="#">Home</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Catalog</a></li>
<li class="bc-13__item"><a class="bc-13__link" href="#">Tools</a></li>
<li class="bc-13__item"><a class="bc-13__link" aria-current="page" href="#">Power Drills</a></li>
</ol>
</nav>
```
## CSS
```css
.bc-13 {
width: 100%;
min-height: 100vh;
--h: 44px;
--depth: 14px;
--page: oklch(0.96 0.01 90);
font-family: system-ui,'Segoe UI',sans-serif;
padding: 30px;
background: var(--page);
display: flex;
align-items: center;
justify-content: center;
}
.bc-13 * {
box-sizing: border-box;
}
.bc-13__list {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
.bc-13__item {
display: flex;
position: relative;
}
.bc-13__item + .bc-13__item {
margin-inline-start: calc(var(--depth) * -1);
}
.bc-13__link {
position: relative;
display: flex;
align-items: center;
height: var(--h);
padding: 0 calc(var(--depth) + 12px) 0 calc(var(--depth) + 12px);
font: 600 13px/1 system-ui,sans-serif;
color: #fff;
text-decoration: none;
background: oklch(0.58 0.03 90);
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%,var(--depth) 50%);
transition: filter .18s ease;
}
.bc-13__item:first-child .bc-13__link {
clip-path: polygon(0 0,calc(100% - var(--depth)) 0,100% 50%,calc(100% - var(--depth)) 100%,0 100%);
padding-left: 16px;
}
.bc-13__item:last-child .bc-13__link {
clip-path: polygon(0 0,100% 0,100% 100%,0 100%,var(--depth) 50%);
padding-right: 16px;
background: oklch(0.6 0.18 25);
}
.bc-13__item:first-child:last-child .bc-13__link {
clip-path: none;
}
.bc-13__item:nth-child(2) .bc-13__link {
background: oklch(0.52 0.05 60);
}
.bc-13__item:nth-child(3) .bc-13__link {
background: oklch(0.5 0.07 40);
}
.bc-13__link:hover {
filter: brightness(1.12);
}
.bc-13__link:focus-visible {
outline: 3px solid oklch(0.3 0.05 40);
outline-offset: 4px;
}
@media (prefers-reduced-motion: reduce) {
.bc-13__link {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — arrows are transparent-border triangles (::after in the crumb colour, ::before in the page colour) that notch together seamlessly; the widest-support arrow technique. */
```How this works
This is the border-triangle heritage technique, still worth knowing. Each crumb is a rectangle; its right-pointing arrow is an ::after triangle formed by the old transparent-border trick — a zero-size box with a thick border-left in the crumb's colour and transparent top/bottom borders, which renders as a solid triangle pointing right. A matching ::before triangle in the PAGE background colour notches into the crumb's left edge, so consecutive crumbs interlock seamlessly without overlap math.
Because the arrow colour is a real border, the trail's tonal palette flows through the triangles automatically as long as each crumb sets its ::after border-left-color to match its own background. It's more verbose than clip-path (demo 01) but has the widest possible support and no clipping of focus outlines — the ring renders normally around the rectangle. The current crumb takes the accent (and its arrow), and the first crumb's incoming notch is simply omitted for a clean start.
Make it yours
- Arrow size = the triangle's border widths; keep the vertical borders half the crumb height for a clean 45°-ish point.
- Palette: set each crumb's background AND its
::afterborder-left-color together (one variable per crumb) so the arrow always matches. - Add a 1px gap-line between crumbs by insetting the notch triangle slightly.
- Swap to a chevron (outline) look by using two thin rotated bars instead of a filled triangle.
Gotchas — read before shipping
- The arrow's
border-left-colorMUST equal the crumb's background, and the incoming notch MUST equal the PAGE background — mismatch and the seam shows. - Triangle borders don't scale with content — set the vertical border widths to exactly half the crumb height or the point looks off-centre.
- This predates
clip-path; if you don't need legacy support, demo 01's clip-path is simpler to maintain — pick per your browser floor. - Keep the triangles
pointer-events:noneso the pointed tip doesn't steal clicks from the neighbouring crumb.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 15.4+ | 113+ | 111+ |
Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome all.
The transparent-border triangle trick works in every browser ever shipped — this is the maximum-compatibility arrow breadcrumb. oklch() palette is the only 2023 touch.