Breadcrumb Navigation with CSS Triangles

Chris Coyier //

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.

View Demo   Download Files

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 unstyle it, 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 Helvetica, Arial, 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 it's 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 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;
}

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

If you end up using this somewhere, let me know. Many pleasure to me this bring.

View Demo   Download Files

Also, see Jesper Ek's idea for using this for steps in a multi-page process.

Update May 27, 2011: Another (different but interesting) take by Rowan Lewis and myself.