Grow your CSS skills. Land your dream job.

Breadcrumb Navigation with CSS Triangles

Published by 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.

Comments

  1. Sweet. Very impressive what you can do with slightly modern CSS. I still don’t get how the border makes the triangle though!

  2. Havvy
    Permalink to comment#

    Shouldn’t that be wrapped inside a tag? I would think it be smarter to do then to put it inside the ul.

  3. Arbyn Acosta
    Permalink to comment#

    Nice Navigation Chris! But it doesn’t work on IE. I thought it was Cross-Browser Compatible

    But anyways, this is a great article! Thanks!

    • Read the section “Deeper Browser Compatibility” in the article above for some tips on how you can start working on that yourself.

    • Matt Gibson
      Permalink to comment#

      Wow! Just tried to see the demo in IE6, but I started by trying to load this article in it, and that was as far as I could get! Is CSS-tricks purposefully that broken for IE6? I mean, it seems actively, _playfully_ non-functional in that browser…

    • I don’t intend to support IE 6 on this site, sorry. I also don’t want this to turn into an IE 6 conversation, so subsequent replies will be buried. (No hard feelings, I appreciate the feedback!)

  4. If you drag the link away (in Firefox at least) you can see what the css is actually doing.

    Otherwise, this is more or less what I had implemented for the site I am currently working on, until I needed to use a gradient background that is..

  5. James
    Permalink to comment#

    I’ve began to use a greater than symbol for the triangles in breadcrumbs lately, they’re a lot easier to work with!

  6. Permalink to comment#

    Good new way to change breadcrumb.. Thanx Chris

  7. Nice technique. The bit I didn’t see in the article was the style used to turn off the triangle after the last breadcrumb. From the code it’s a nice.

    .breadcrumb li:last-child a:after { border: 0; }

    I guess a similar before selector could be used if the overall background wasn’t white.

  8. Permalink to comment#

    Wow! I’m an avid reader of your blog, and don’t usually comment, but this one really caught my eye! Great idea and beautiful implementation

  9. Mr Lol
    Permalink to comment#

    Why are you setting both display block and float left, surely you just need float left as the element would behave like display inline block ?

  10. Permalink to comment#

    Very cool technique. This could very easily be made more functional in IE 8 with about ten more minutes of work. I was impressed with the technique, but definitely rough around the edges.

    • If you got those 10 minutes, I got an article update with your name on it.

    • Instead of using nth-child, you could apply class names such as level-1 to each <li>. Since you are already calling nth-child so much in the CSS for the lightening colors, you might as well.

      Doing this, along with adding z-index starting with 1 at the lowest level and ending at (for this example) 5 at the highest level, and using rgb instead of hsla, gives you IE8 support.

      Test case on Snipplr

  11. Chris the Developer
    Permalink to comment#

    Looks terrible in Chrome (6.0.472.63) OSX SL… Just sayin’

    • Looks fine to me in Chrome 8. http://cl.ly/34Ee

      It doesn’t seem like there is anything in here that Chrome 6 wasn’t fully capable of. If you find a fix, please let us know so we can update this. I feel like there should be some clever saying like “if you got time to lean you got time to clean”, only like “if you have time to comment about problems, you have time to code a fix.”

    • Chris the Developer
      Permalink to comment#

      I was referring to the edge of the triangles – you can see in your screenshot how jagged they are… :)

    • Chris the Developer
      Permalink to comment#
  12. Chris the Developer
    Permalink to comment#

    …this does seem to be related to the sharpness of the triangle border though…at 90 degree angles chrome renders them beautifully.

    • Ah yes, definitely the “squatter” triangles render way worse. Not sure what’s up with that. 90-degree triangles are typically much cleaner. The white triangle really emphasizes the crappy rendering, so if you just remove the :before triangle, that looks much cleaner too.

    • Chrome is rubbish at anti-aliasing certain effects, so it leaves jaggies on anything that doesn’t easily fit into straight pixels (a 45 degree line is fine because it just puts the diagonal pixels on, but anything other than 45 degrees will alias). Having said that, on Chrome 7 Windows 7 the demo is perfectly smooth :)

  13. Really a great article Chris! I really love the design of this breadcrumb…
    I can’t wait to see full CSS3 support on every browser.

  14. Permalink to comment#

    not working for me in IE7,

    Al

  15. I created pretty much the same thing a year ago (though not for breadcrumbs):

    http://cl.ly/1f8177a6147a07371650

    Works in:

    PC IE6/7/8, Firefox 3+, Safari 4+, Chrome 4+, Opera 10.5+
    Mac Firefox 3+, Safari 4+ (untested in Chrome, only have Tiger on my MacBook)

    Markup is an unordered list, uses sprites and had to use JavaScript to get it to work in IE6 only, I think. Without JS in IE6, I think the boxes just render with a squared off right side (been a while since I built it).

    The site is still in development (internal dev failure which was then outsourced, which has slipped dates a couple times!) but is scheduled to launch by end of year. We’ll see if it still works come launch, which I don’t have a lot of faith in as the vendor has said they haven’t even done any cross browser testing yet (yikes).

    If I remember, I’ll come back here and post up a link when it’s live.

  16. Permalink to comment#

    images looks better and smooth

  17. Nice stuff until it works in damn IE. Thanks for sharing :)

  18. Permalink to comment#

    sweet… dint now we can make triangles from css… will apply this trick to my next project :)

  19. Permalink to comment#

    good idea chris

  20. there’s no reason to use hsla when it’s opaque, use hsl

    hsl(8%, 100%, 50%)

    • Alternatively, there’s no reason to alter the Lightness property of HLSA when on a white background, make it more transparent.

      hsl(8%, 100%, 50%, 1)
      hsl(8%, 100%, 50%, .8)
      hsl(8%, 100%, 50%, .6)

  21. Jonny007-MKD
    Permalink to comment#

    I really like this one :) great!

  22. Permalink to comment#

    very creative use of CSS!
    the color scheme reminds me of the RV from Breaking Bad

  23. Proof of concept CSS3 only, with gradient backgrounds and borders.

    http://jsfiddle.net/qXCed/5/

    (Webkit and FF4 only though)

  24. Bob
    Permalink to comment#

    In IE9 beta it looks a bit weird…

  25. Permalink to comment#

    The same idea is used in http://zemz-ua.com/en/about language switcher/ Just for fun.

  26. Love it! Simply love it! Thanks so much for sharing. By the way @Jeremy, yours is great too.
    Probably it wont work in IE… Anybody knows?

  27. Great tutorial. Breadcrumbs have never looked so beautiful earlier.

  28. What an innovative solution. Thanks for taking the time to put this together.

  29. lol – i don’t intend to support ie6, i have a good laugh. apart from that ninja article Chris, thanks.

  30. Without wanting to start a semantics war here, I don’t think there is anything wrong with the markup. The problem with semantics is that it is subjective.

    My own view on breadcrumbs is that they are an ordered list, as they appear in a defined logical order. It doesn’t make me right and you and Chris wrong.

    Great article Chris. I love the new tings that are becoming possible with CSS, I just wish that more of the other developers I work with shared that opinion.

  31. I think Geert has a good point about an unordered list not being the most perfectly semantic thing. I also don’t think a paragraph tag is the right answer. This is where my mind goes first, but it seems WAY overkill:

    <ul class="breadcrumb">
        <li>
          <a href="#">Top Level</a>
          <ul>
            <li>
              <a href="#">Second Level</a>
              <ul>
                 <li>
                   <a href="#">Third Level</a>
                   <ul>
                      <li>
                         Current Item
                     </li>
                   </ul>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    • I think an ordered list would be fine semantically (because the order of the breadcrumbs matter), and is simple.

      The difference between using an <ol> and a bunch of nested <ul>s is how you perceive the way breadcrumbs work.

      For the <ol> case:

      Begin at “Top Level”
      Continue to “Second Level”
      Continue to “Third Level”
      Finish at “Current Item”

      For the nested <ul> case:

      Begin at the list of links in the “Top Level”
      Choose “Second Level” from the next list of choices
      Choose “Third Level” from the next list of choices
      Choose “Current Item” from the next list of choices

      I suppose it depends on whether you want to view it as a direct path/causal relationship (<ol>) or as a series of choices showing only the chosen items (<ul>).

  32. Geert van der Heide
    Permalink to comment#

    @Thomas: Semantics are subjective to an extend, I agree, but some things are just wrong and this is one of them. On the other hand, in the specific case of a breadcrumb, there isn’t a definitive right solution either. Using an unordered isn’t horrible, but it’s not correct. And I don’t think that’s subjective. What anyone ends up using is their own choice of course.

    @Chris: The example you posted is maybe a little better in terms of semantics, but obviously it’s horribly convulated as you point out. As said, I think there is no definitive semantically correct solution for a breadcrumb, which is why I decided to keep it simple (p-tag containing a-tags). If every solution has its downsides than I’ll choose the simplest in this case. But to each his own.

    An interesting discussion either way, and something I think could have been addressed better during the development of HTML5.

    • Geert, my take on this is that the breadcrumbs are an aid to navigation, not a description of the site hierarchy. From the point of view of the HTML document the breadcrumb trail is a list of links that can be used to navigate back up the site tree. To me this supplemental to the topic of the document so I wouldn’t go into too much detail for it.

      However, if the topic of the document is describing the site hierarchy then I would say a list just wouldn’t cut the mustard.

      But on the other hand breadcrumbs also show you where in the hierarchy you are so it can easily work both ways!

      Hope this makes sense.

  33. Chris
    Permalink to comment#

    I agree with Thomas Heaney, an ordered list makes perfect sense here.

  34. Permalink to comment#

    I like james use of the greater or less than symbol.

  35. Cool.. Love it!

  36. Excellent article, love the design of the breadcrumb, will try and use this maybe for a navigation pointer. LT

  37. Permalink to comment#

    This is a great technique as it is really cool, you can use it as a pointer on a tooltip too. Too bad it isn’t compatible with older browsers though.

  38. Permalink to comment#

    This is what i’ve been looking for :D Thank you so much :)

  39. This is a great tutorial. Very helpful. Thanks!

  40. Edison A. Leon
    Permalink to comment#

    Simply awesome, I can work around for old browser only if there’s a really motive to do so, other than that it will just gratefully degrade with no nice tricks, I had it with IE.

  41. Permalink to comment#

    It’s awesome! I really like it, thank you so much!

  42. Any suggestions how to implement css arrows with div only breadcrumbs? Thanks.

  43. Nice idea but not really browsercompatible. Although i am going to use it :)

  44. as usual awesome work :) thanks

  45. Permalink to comment#

    It is very nice making triangles with out using images. Still I dont understand How he did it. I have to go through it.

    thanks
    vara

  46. Where was this tutorial months ago when I needed to code exactly this kind of breadcrumb??? :P AWESOME technique Chris.

  47. gnemok
    Permalink to comment#

    nice. realy helpfull

  48. Anji
    Permalink to comment#

    hi sir i can have small doubt. which property we can use the mouse over after click the menu item color will fixed and go to click next item thats can be change in fixed . how is it possible.
    using the property can tell me sir…

Leave a Comment

Current day month ye@r *

*May or may not contain any actual "CSS" or "Tricks".