Grow your CSS skills. Land your dream job.

Exploring Markup for Breadcrumbs

Published by Chris Coyier

In the comments for my recent post about CSS Triangle Breadcrumbs, the HTML markup I used to create them was (in essence):

<ul class="breadcrumb">
  <li><a href="#">Top Level</a></li>
  <li><a href="#">Second Level</a></li>
  <li><a href="#">Third Level</a></li>
  <li>Current Item</li>
</ul>

To which Geert van der Heide commented:

... the HTML is not semantic. Coding a breadcrumb as an unordered list makes it seem like the items are on the same hierarchical level, like it's a set of items in a row. The items in a breadcrumb are not, they represent a path, with each link being a "child" of the last.

I thought it was a good point. An unordered list, semantically, does feel wrong. Like Geert said, it puts them all on the same hierarchical level. To get each menu item clearly onto its own level, markup like this would be required:

<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>

That's feels pretty overwhelming though doesn't it? I can't see that being used, even though technically you could and get it styled just about any way you need it.

No, the "unordered" part of an unordered list is more the problem. Perhaps we could just make it an ordered list instead:

<ol class="breadcrumb">
  <li><a href="#">Top Level</a></li>
  <li><a href="#">Second Level</a></li>
  <li><a href="#">Third Level</a></li>
  <li>Current Item</li>
</ol>

That definitely feels better. Breadcrumbs are in a very specific order and so using an "ordered" list seems appropriate. I'm somehow not totally satisfied by that though. Just because a list is 1, 2, 3, etc, doesn't really represent layers of hierarchy.

Several folks also mentioned just using links and some kind of textual visual separator.

<p class="breadcrumb">
  <a href="#">Top Level</a> >
  <a href="#">Second Level</a> >
  <a href="#">Third Level</a> >
  Current Item
</p>

Without any CSS styling at all, this is probably the most effective. The > symbol separator indicates hierarchy pretty well. Using inline elements gives the breadcrumbs a horizontal layout like breadcrumbs typically have. Again though, this isn't terribly satisfying as the markup itself doesn't describe what it holds very meaningfully.

I thought I'd go check out if Google had any advice on this subject. After all, Google features breadcrumbs in their search results:

Unsurprisingly, the markup of their actual search results is just a silly mess (the markup of Google-anything is a silly mess). They do, however, have something to say about how we should markup our breadcrumbs. They recommend HTML5 Microdata, and offer this example:

<div itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
  <a href="http://www.example.com/books" itemprop="url">
    <span itemprop="title">Books</span>
  </a> ›
  <div itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
    <a href="http://www.example.com/books/authors" itemprop="url">
      <span itemprop="title">Authors</span>
    </a> ›
    <div itemprop="child" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
      <a href="http://www.example.com/books/authors/stephenking" itemprop="url">
        <span itemprop="title">Stephen King</span>
      </a>
    </div>
  </div>
</div>

Looks clumsy at first glance, but actually microdata is intended for just such purposes. I'd probably go with spans here, instead of the div wrappers regardless.

I'm not sure how microdata and microformats relate to one another, but it seems like microformats suggests just giving the wrapper a class name of 'breadcrumb' and calling it a day.

HTML5 has a bit more to say on the subject (see update below) Using the "up" value in a rel attribute signifies that element is part of a hierarchical structure and also indicates the distance from the current document to the reference document.

<nav>
 <p>
  <a href="/" rel="index up up up">Main</a> >
  <a href="/products/" rel="up up">Products</a> >
  <a href="/products/dishwashers/" rel="up">Dishwashers</a> >
  <a>Second hand</a>
 </p>
</nav>

The nav tag is especially appropriate, and any of the code examples above would benefit semantically from being wrapped in it. Aside from that, this may be the most satisfying of all the examples to me as it semantically describes the nature of a breadcrumb. The rel tag is specifically for describing relationships between elements, so that is a fit. Also visually, without any styling, the breadcrumb look is accomplished.

But please note: the rel/up thing is not final and isn't likely to last. There is an open issue which indicates using multiple "up"s isn't a very clean way to do things and suggestions for values like "up2", "great-grandparent" or even a new attribute like level="3" are going around.

Update: Nelson Menezes wrote in to let me know HTML5 and rel="up" is dead. References: 1 2

So where are we at on this? I'd say that there is no super-ultimate best-possible-way to handle breadcrumb markup yet. Hopefully obviously, this really isn't a big deal. Just pick one that works for you and go with it. I just think it's interesting territory for an HTML conversation. If you have any ideas for breadcrumb markup not shown here, please share!

Comments

  1. I’d say this is an interesting jumping off point for a discussion on the overcomplication of some markup for the sake of it.

    I usually use an unordered list but I can see the various pros and cons of all the approaches but on balance I think I’ll probably stick with an UL.

    J.

  2. Permalink to comment#

    So many way to skin a cat. Chris you are the master. thanks

  3. Hi, the method I like the most is in the 4th example. To make breadcrumb I use paragraph tag inside which I put normal links and span for current page.

  4. Permalink to comment#

    I think I’d go for ULs inside LIs. That way you can add the rest of the sections of the site and have them hidden, and then use some JS to show them on roll-over, for example. That’d be a quick way of navigating through a site!

  5. Permalink to comment#

    I also like the 4th example, because it balances simple markup with accessibility. I’m thinking of how each example would appear with CSS turned off. However, it is a bit more difficult to style. I think a nested UL is the most semantic in terms of representing the actual meaning of the breadcrumbs, and it may not look as nice in a text browser, but it would still make sense. The markup seems daunting, but it’s not really so bad. I would try formatting it like this;

    <ul><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>
    • Permalink to comment#

      Ooops. Maybe this;

      <ul><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>
  6. Permalink to comment#

    I usually go with your first example (as used in previous triangle post as well). Why does it matter if it doesn’t contain semantic hierarchy?

    • The reason semantics matters is so that our final document represents with perfect clarity the content that it describes. This matters to people reading that document without the assistance of CSS or other technologies to visually describe what that content is. I suppose there is some chance that, when a user faced with interacting with an unordered list that had no indication that it was a breadcrumb, would just see it as a list of navigation and not understand it’s representative of hierarchy.

      If we are to give up on trying to describe things semantically with HTML, then we are to give up on accessibility, and we might as well just make everything on the page a <div>

  7. Permalink to comment#

    Very interesting point of view Chris!

    I think we should just keep it simple, as an simple list seems semantic enough for me and I’m not seeing myself (or other developers) using hierarchical list to soon for this type of matter.

  8. Permalink to comment#

    While I agree that we need to use the most semantic markup possible, I think some of these “solutions” are a little bit over-complicated. There has to be a middle ground between semantic perfection and real-world usage. For me atleast, that is an ordered list or perhaps method number 4.

  9. To say Google recommends microdata is a little shortsighted. Google recommends microdata or RDFa. While I’m a fan of the syntax of microdata, I have found as the User Experience Director for motorcycle-superstore.com that: While Google recommends microdata, they don’t actually like it all that well when compared to RDFa — for our specific purpose — when cataloging product and product reviews.

    I hope this changes in the future, but this has been our experience.

  10. Permalink to comment#

    I actually do not like the exprestion “So many way to skin a cat”.

    .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;
    }
    .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;
    }
    .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;
    }
    .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 a:hover { background: hsla(34,85%,25%,1); }
    .breadcrumb li a:hover:after { border-left-color: hsla(34,85%,25%,1) !important; }
  11. Batfan
    Permalink to comment#

    While this was definitely an interesting read, I’ll likely stick with UL’s for now. I agree with Adrian in that the quest to for a site to be fully semantic often seems to greatly over-complicate things. There has to be a middle ground.

    “This matters to people reading that document without the assistance of CSS or other technologies to visually describe what that content is.”

    I agree with you here but, the chance of someone visiting your site with CSS disabled (or unavailable to them) is very, very slim. Furthermore, if that is the case, they would likely be able to determine that the list was a set of breadcrumbs, given the contained links and its location in the page structure.

    • Permalink to comment#

      quote: “the chance of someone visiting your site with CSS disabled (or unavailable to them) is very, very slim.”

      What about visually impaired people that rely on screenreaders for example? Semantic code is crucial for the way screenreaders interpret code. Slim or not slim, it could be seen as discrimination if you don’t write semantic code. This is the reason why Dutch goverment for example has strict rules about their own websites. Because of freedom of information and all.

  12. James
    Permalink to comment#
    <nav>
    
    	<fieldset class="breadcrumb"> 
    	
    		<span class="crumbs"> 
    		
    			<span class="crust" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb"> 
    			<a href="http://xenforo.com/" class="crumb" rel="up" itemprop="url"><span itemprop="title">Home</span></a> 
    			<span class="arrow"><span></span></span> 
    			</span> 
    
    			<span class="crust" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> 
    			<a href="http://xenforo.com/community/" class="crumb" rel="up" itemprop="url"><span itemprop="title">Forums</span></a> 
    			<span class="arrow"><span>></span></span> 
    			</span> 
    
    			<span class="crust" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> 
    			<a href="http://xenforo.com/community/#public-forums.17" class="crumb" rel="up" itemprop="url"><span itemprop="title">Public Forums</span></a> 
    			<span class="arrow"><span>></span></span> 
    			</span> 
    
    			<span class="crust" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> 
    			<a href="http://xenforo.com/community/forums/bugs/" class="crumb" rel="up" itemprop="url"><span itemprop="title">XenForo Bug Reports</span></a> 
    			<span class="arrow"><span>></span></span> 
    			</span> 
    
    		</span>
    		
    	</fieldset>
    	
    </nav>

    That is the syntax used for breadcrumbs over on XenForo Community Forums and it does seem a good syntax to use!

    • Chris
      Permalink to comment#

      Empty span tags in that markup would be considered semantically poor though wouldn’t it?

    • James
      Permalink to comment#

      I was under the impression that span, just like div, held no semantic value whatsoever. I could be mistaken however.

    • Permalink to comment#

      Except that fieldset is only supposed to be used in forms.

      Replacing the fieldset with a div is still possible.

  13. Chris
    Permalink to comment#

    Empty span tags in that markup would be considered semantically poor though wouldn’t it?

  14. I think the most semantic way to mark up breadcrumbs is to use the HTML5 Nav element as you did in the 4th example. However, I believe it’s better to use an ordered list (rather than anchor tags with redundant up’s in the rel attribute) to represent a sequence of items.

    Here’s how I would do it…

    
         <!-- Breadcrumb Navigation -->
    	<!-- Sequence of Items-->
    	    <a href="" rel="nofollow">Home</a>
    	    <a href="" rel="nofollow">Genres</a>
                <a href="" rel="nofollow">Jazz</a>
       
  15. Correction: example 6

  16. I use an ordered lists on the rare occasions I use breadcrumbs. There’s a definite order to the list but it’s not a full on navigation system so doesn’t warrant the nested lists.

  17. DJ
    Permalink to comment#

    It seems to me that worrying about semantics is like worrying about validation – if it’s useful then use it or worry about it. Its usefulness and importance speaks for itself, no one speaks against them, but no one lets them become their whole goal in coding either. Turning a 5-line piece of code into a 15-20 line code requiring 3 times the typing seems absurd on the face of it. If we’re so worried about it being understood one simple “comment” on one line would do the trick.

    Agreeing that HTML SHOULD be semantic – it should be more up to the “powers that be” to give us tags that ARE semantic: like or or (linear list) or etc. etc.. It seems to me that this rises to at least the same level of importance as a “definition list” and the working group gave us for them! Browsers could merely parse and identically except defaulting to in-line block for the .

  18. DJ
    Permalink to comment#

    Sorry – I just can’t get used to the way ya’ll handle < and > in a comment box – and no edit function.

    Above last paragraph should read:

    Agreeing that HTML SHOULD be semantic – it should be more up to the “powers that be” to actually give us tags that ARE semantic: like <breadcrumb> or <bread> or <ll> (linear list) or <hl> (horizontal list), etc. etc.. It seems to me that this rises to at least the same level of importance as a “definition list” and the working group gave us <dl> for them! Browsers could merely parse <ll> and <ul> identically except defaulting to in-line block for the <ll>.

  19. Permalink to comment#

    Deja vu 1 2

  20. Excellent examples of markup for breadcrumbs, we usually follow closely to example 4, although using divs and know we should really change this to a paragraph tag. LT

  21. HrvojeKC
    Permalink to comment#

    As breadcrumbs are a list of links I would put links inside list items and the links are in certain order I would use the ordered list element, and as it is a navigational element I would wrap the ordered list inside a nav element with the class of breadcrumb (does the role=”breadcrumb” exists?)

    <nav class="breadcrumb">
        <ol>
            <li><a href="#">Top Level</a></li>
            <li><a href="#">Second Level</a></li>
            <li><a href="#">Third Level</a></li>
            <li>Current Item</li>
        </ol>
    </nav>
  22. Dan
    Permalink to comment#

    This is based on the list being a ‘where you are’ in the hierarchy of the – which to be honest, is how I, and I’m sure most people populate the content of a breadcrumb trail.

    But… I’m sure I read some where that a breadcrumb trail (by virtue of its name) is not where you are, but how you got there – which may not map to the hierarchy of a site. In which case the ordered list would be more appropriate instead?

    What do you think?

  23. Permalink to comment#

    Shouldn’t you escape the “>”s? Just a thought…

  24. Bonde
    Permalink to comment#

    I would be nice if HTML5 did away with the need to explicitly wrap each nested list in it’s ol or ul:

    <nav>
    	<ul>
    		<li>
    			Top Level
    			<li>
    				Next Level
    				<li>
    					Current Level
    				</li>
    			</li>
    		</li>
    	</ul>
    </nav>

    I may be missing something big but that seems to carry enough info to convey you are nesting lists. It would allow for semantically describing a breadcrumb and help keep the code bloat down. I guess there would be instances where you might have an ordered list nested in an unordered list but then you would just explicitly set it in that case.

  25. Good point Chris.

    W3C itself using this code http://www.w3.org/standards/semanticweb/

    <a href="#w3c_content_body" title="Skip to content (e.g., when browsing via audio)" rel="nofollow">Skip</a>
            <a href="/" rel="nofollow">W3C</a> » 
            <a href="/standards/" rel="nofollow">Standards</a> » 
            Semantic Web
  26. Permalink to comment#

    great
    do you prefer breadcrumb divider using > or image or maybe &raquo ?

  27. Jim
    Permalink to comment#

    Just to add to my previous post.

    Text separators could also be added using CSS.

    Entity codes do not work using this method (use utf-8).

    CSS

    #breadcrumbs span[itemtype]:after {
    	padding: 0 5px;
    	content: "»";
    }
  28. Nice article, Chris, and a topic that, through a curious coincidence, I approached a href=”http://demosthenes.info/blog/220/Breadcrumb-navigation-with-PHP”>on my blog today. I’ve always preferred the nested-unordered-list approach, for all the reasons mentioned so far: it makes the most semantic sense, works well with no CSS, and is easy to style (I use :before to generate the separators, as it provides greater control and variation, less typing, and more consistency.) I appreciated the heads-up on possible approaches in HTML5 – I shall definitely link this article as recommended reading to the blog entry.

  29. Permalink to comment#

    I am a newbie at HTML and CSS. Here is my attempt to adapt the breadcrumbs to IE.

    CSS

    .crumb {
    	list-style: none;
    	overflow: hidden;
    	font: 18px Helvetica, Arial, Sans-Serif;
    }
    
    .crumb li {
    	float: left;
    } 
    
    .crumb li a {
    	color: white;
    	text-decoration: none;
    	margin-left: 33px;
    	padding: 5px 0 5px 25px;
    	background: #666; 
    	position: relative;
    	display: block;
    	float: left;
    	z-index: 1;
    }
    
    .crumb li a:before {
    	content: " ";
    	display: block; width: 0;
    	height: 0;
    	border-top: 50px solid #666;
    	border-bottom: 50px solid #666;
    	border-left: 30px solid transparent;
    	position: absolute;
    	top: 50%;
    	margin-top: -50px;
    	margin-left: 3px;
    	left: -33px;
    	z-index: 10;
    }
    
    .crumb li a:after {
    	content: " ";
    	display: block;
    	width: 0;
    	height: 0;
    	border-top: 50px solid transparent;  
    	border-bottom: 50px solid transparent;
    	border-left: 30px solid #666;
    	position: absolute;
    	top: 50%;
    	margin-top: -50px;
    	left: 100%;
    	z-index: 5;
    }
    
    
    .crumb li a:hover { 
    	background: #900; 
    	position: relative;
    	display: block;
    	float: left;
    	z-index: 1;
    }
     
    
    .crumb li a:hover:before {
    	content: " ";
    	display: block; width: 0;
    	height: 0;
    	border-top: 50px solid #900;
    	border-bottom: 50px solid #900;
    	border-left: 30px solid transparent;
    	position: absolute;
    	top: 50%;
    	margin-top: -50px;
    	margin-left: 3px;
    	left: -33px;
    	z-index: 10;
    }
    
    .crumb li a:hover:after { 
    	border-left-color: #900;
    	position: absolute;
    	top: 50%;
    	margin-top: -50px;
    	left: 100%;
    	z-index: 5;
    }
    
    .currentpage {
    	border: 0;
    	background-color: #333;
    	color: white;
    	text-decoration: none;
    	margin-left: 33px;
    	padding: 5px 25px;
    	position: relative;
    	display: block;
    	float: left;
    	z-index: 1;
    }

    HTML

    <ul class="crumb">
    	<li><a href="#">Home</a></li>
    	<li><a href="#">Link 1</a></li>
    	<li><a href="#">Link 2</a></li>
    	<li><a href="#">Link 3</a></li>
    	<li class="currentpage">Current</a></li> 
    </ul>
  30. Permalink to comment#

    I always use a regular set of links, no list or anything fancy. It’s easiest to manage, update, and read.

    …except I should point out: Don’t forget to encode your Greater Than (gt; or >) symbol. :D

    • You actually don’t really need to. Sometimes it’s nice when it’s matched with an opening less than sign (like an HTML tag), but it’s only the opening one that really needs to be encoded to prevent problems.

This comment thread is closed. If you have important information to share, you can always contact me.

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