Did you know you can make triangles with pure CSS? It's pretty easy. You just make a block level element with zero width and height, a colored border on one side, and transparent borders on the two adjacent sides. They are fun for all kinds of things, like little arrow sticking out from speech bubbles, navigation pointers, and more. Often times these are just visual flourishes, undeserving of dedicated markup. Fortunately, pseduo elements are often a perfect fit. That is, using ::before, ::after, or both to create these block level elements and place the triangle. One neat use that came to mind in this vein: breadcrumb navigation.

The HTML Markup

Let's keep things as absolutely clean as possible, and go with a simple unordered list with a "breadcrumb" class:

<ul class="breadcrumb">
  <li><a href="#">Home</a></li>
  <li><a href="#">Vehicles</a></li>
  <li><a href="#">Vans</a></li>
  <li><a href="#">Camper Vans</a></li>
  <li><a href="#">1989 VW Westfalia Vanagon</a></li>
</ul>

The CSS

First, we'll ensure our list doesn't look like a typical list. We'll remove the default list styles, float the items to the left and set up very basic styling for each link. Note the hidden overflow on the list itself, this will be useful for two reasons. One, it ensures the menu has a height. Containers that contain only floated elements collapse, which is often not ideal. Two, when we make our triangles, we're going to make them big.

.breadcrumb { 
  list-style: none; 
  overflow: hidden; 
  font: 18px Sans-Serif;
}
.breadcrumb li { 
  float: left; 
}
.breadcrumb li a {
  color: white;
  text-decoration: none; 
  padding: 10px 0 10px 65px;
  background: brown; /* fallback color */
  background: hsla(34,85%,35%,1); 
  position: relative; 
  display: block;
  float: left;
}

To create the triangle, we'll use the ::after selector to make a pseudo element. It will be block-level, of zero height and width, and absolutely positioned 100% to the left, which means it will begin at the right edge of its parent. We'll position it 50% from the top, and pull it back up -50px with margin, which will ensure it is absolutely centered. This is a classic trick. A few other things to note. The borders we'll use are 50px on the top, 50px on the bottom, and on the left (making a right facing arrow) only 30px. This means a more flat-faced arrow. If we went higher than 50px it would be more sharp-tipped. Equal to 50px would make it a perfect 90 degrees. Because the top and bottom borders are 50px each, that makes the height of the arrow 100px. 100px is far taller than our menu is likely to be with its 18px font size and 10px of top and bottom padding. This is a good thing. It means we have plenty of room to play with tweaking the font size without worrying the triangle will show its limit.

.breadcrumb li a::after { 
  content: " "; 
  display: block; 
  width: 0; 
  height: 0;
  border-top: 50px solid transparent; /* Go big on the size, and let overflow hide */
  border-bottom: 50px solid transparent;
  border-left: 30px solid hsla(34,85%,35%,1);
  position: absolute;
  top: 50%;
  margin-top: -50px; 
  left: 100%;
  z-index: 2; 
}

Notice the little 1px white line of separation? That's another little trick. We can't add a border directly to the triangle because it's already made of a border! Instead, we'll make another triangle, and set it behind our original triangle, and color it white. This one uses the ::before selector, but is otherwise exactly the same. Note that the z-index is what is important here. You could switch around which triangle uses ::after and which uses ::before, it really doesn't matter.

.breadcrumb li a::before { 
  content: " "; 
  display: block; 
  width: 0; 
  height: 0;
  border-top: 50px solid transparent;       
  border-bottom: 50px solid transparent;
  border-left: 30px solid white;
  position: absolute;
  top: 50%;
  margin-top: -50px; 
  margin-left: 1px;
  left: 100%;
  z-index: 1; 
}

Now onto the coloration. Since we are going a touch progressive here, there are two bits of CSS I think are perfect matches for this idea: nth-child and HSLa.

  • The cool part about nth-child: we can color the different levels of the breadcrumb with no additional markup
  • The cool part about HSLa: we can color the different levels of the breadcrumbs based on a single hue with different shades very easily

In addition to the colorization, we'll make the first link have less left padding (less needed single a triangle isn't up in its grill) and we'll make the last link not have any coloring at all as well as not respond to clicks or show a pointer cursor. We can do these also with no additional markup needed through :first-child and :last-child.

.breadcrumb li:first-child a {
  padding-left: 10px;
}
.breadcrumb li:nth-child(2) a       { background:        hsla(34,85%,45%,1); }
.breadcrumb li:nth-child(2) a:after { border-left-color: hsla(34,85%,45%,1); }
.breadcrumb li:nth-child(3) a       { background:        hsla(34,85%,55%,1); }
.breadcrumb li:nth-child(3) a:after { border-left-color: hsla(34,85%,55%,1); }
.breadcrumb li:nth-child(4) a       { background:        hsla(34,85%,65%,1); }
.breadcrumb li:nth-child(4) a:after { border-left-color: hsla(34,85%,65%,1); }
.breadcrumb li:nth-child(5) a       { background:        hsla(34,85%,75%,1); }
.breadcrumb li:nth-child(5) a:after { border-left-color: hsla(34,85%,75%,1); }
.breadcrumb li:last-child a {
  background: transparent !important;
  color: black;
  pointer-events: none;
  cursor: default;
}
.breadcrumb li:last-child a::after { 
  border: 0; 
}

And finally, hover states. The only trick here is that we need to color the triangle as well as the link. No big deal.

.breadcrumb li a:hover { 
  background: hsla(34, 85%, 25%, 1); 
}
.breadcrumb li a:hover:after { 
  border-left-color: hsla(34, 85%, 25%, 1) !important; 
}

Deeper Browser Compatibility

Call me a lazy sack, but I didn't bother to deal with very deep browser compatibility. I was more excited about the idea than thinking about production. If you want to use this idea, but are concerned about older browsers, here are some things to think about:

Enjoy

Here's the example we covered, and a couple of variations:

See the Pen CSS Triangle Breadcrumbs by CSS-Tricks (@css-tricks) on CodePen.