Styling Nested Lists

Recently, I was building a site map and realized that it is basically an outline of sorts. So how should I go about marking it up? I settled on a series of nested tables — ha! gotcha — nested unordered lists.

The Raw Markup

At their very basic — nested, unstyled lists deliver the exact hierarchy I was looking for. I could feel good about the structure that all browsers and devices would read, while easily styling it with CSS later on.

A simple version might look something like this:


<ul>
<li>Weblog</li>
<li>Articles
   <ul>
   <li>How to Beat the Red Sox</li>
   <li>Pitching Past the 7th Inning
      <ul>
      <li>Part I</li>
      <li>Part II</li>
      </ul>
   </li>
   <li>Eighty-Five Years Isn't All That Long, Really</li>
   </ul>
</li>
<li>About</li>
</ul>

Figure 1 below shows us how the markup above will render in most browsers. Woilla. A site map or outline. But let’s kick it up a notch (apologies to Emeril).

figure 1
Figure 1

Adding Style

Let’s say that we’d like some definition for certain levels of the site map. All we really need to add to the markup is an id so that we may style this particular list differently from any other lists that may be on the same page, without any additional markup:


<ul id="sitemap">
<li>Weblog</li>
<li>Articles
   <ul>
   <li>How to Beat the Red Sox</li>
   <li>Pitching Past the 7th Inning
      <ul>
      <li>Part I</li>
      <li>Part II</li>
      </ul>
   </li>
   <li>Eighty-Five Years Isn't All That Long, Really</li>
   </ul>
</li>
<li>About</li>
</ul>

Using descendant selectors, we can give a unique style to each separate level of the list. For instance, if we’d like the higher levels to be large and bold and the inner levels progressively smaller, we’d first set the size and weight for entire list:


#sitemap {
font-size: 140%;
font-weight: bold;
}

That will make the entire list big and bold. So next we’ll reduce the size and turn off bolding for li elements that are nested at any level below:


#sitemap {
font-size: 140%;
font-weight: bold;
}
#sitemap li ul {
font-size: 90%;
font-weight: normal;
}

figure 2
Figure 2

This means that all top level items will be big and bold, while all lists that are nested within will have a normal weight and font-size of 90% (which in this case is 140% of whatever the page default is). Figure 2 above shows the result.

We don’t even need to assign a smaller size for the third level, as it’ll automatically apply 90% of 90% (a little confusing, but it works!):

Now we have a descending font-size for each level of the list.

Custom Bullets

Let’s turn off default styling, and add a decorative bullet for only third level items by using the background property. We’ll first turn off list styling in general for all li elements, then we’ll specifically assign a background image for third level items:


#sitemap {
font-size: 140%;
}
#sitemap li {
list-style: none;
}
#sitemap li ul {
font-size: 90%;
}
#sitemap li ul li ul li {
padding-left: 16px;
background: url(bullet.gif) no-repeat 0 50%;
}

figure 3
Figure 3

Figure 3 shows the resulting list with a custom bullet applied only to third level li elements. We’ve added 16 pixels of padding on the left to account for the width of the decorative bullet image we’re using (plus a bit of whitespace). We’re also telling the browser to align the image 0 pixels from the left and 50% from the top, which essentially aligns the bullet to the left and center of the text. While we could’ve used a pixel value here, using a percentage allows for similar bullet placement if text is resized.

Conclusion

For building outline-like lists, nesting uls makes for a structurally sound — and easily styled solution. By assigning a single id to the top-level ul, we can let CSS do all the hard work of styling each level separately — without the need for extraneous presentational markup. And possibilities for creative styling go way beyond this simple example.

34 Comments

  1. mini-d says:

    I usually use em instead %, better handling for screens and browsers. The problem of em is inheritance i fixed this adding a new rule to all my CSS files like ul li ul li is equal to … ang so on…

  2. QUiS? says:

    For parts of my site I use this kind of structure, but with only one sub-list, which is displyed inline. This gives a bulleted list of dates, with each date followed by a comma-separated unordered list of site updates for that date. Oh, the possibilities…

  3. Rahul says:

    Good work!
    Perhaps an example that shows how to use CSS to do this but with folder icons a la Windows Explorer’s treeview would be a good thing to have handy in a book or something. A lot of clients want that kind of look on their lists (especially on their site map).
    As for me, I was trying to get definition lists to format inline. Any ideas? Setting display: inline for dl, dt and dd didn’t work…

  4. mini-d…forgive my ignorance, but doesn’t % have exactly the same inheritance issues as em (especially considering that, if i’m not missing anything, ems are essentially the same as percentages: 0.75em = 75% etc) ?

  5. TOOLman says:

    Using em’s rather than percents may be desirable, especially if the text could span more than one line if the window is resized. If the text spans two lines, using 50% will center the icon between the lines. Usually, you’d want to align it with the top-most line.

  6. Rahul, try also setting the list-style-type to none (i.e. list-style-type : none;). It works for me. You can see a sample on my Java page: http://homepage.mac.com/unearthed/software/ (the list of available software is done with a definition list).

  7. Anne says:

    FYI: This works too: #sitemap li li li{ /* styles */, descendent combinators are not the same as child selectors.

  8. web says:

    Can someone say disgruntled Red Sox fan. Cuz’ I can.
    It still hurts me too, swallow the pain.

  9. I’m also using nested unordered lists on my page,
    but i use css and a little script in order to make
    them into a dropdown menu thingy :D
    take a look if ya like :D

  10. Chris Neale says:

    Rahul, what dl, dt, dd effect do want to achieve ?

  11. Chris Neale says:

    display:inline on just dt and dl might be better

  12. Anonymous says:

    This article and Rahul comments reminded me of an idea I had on styling nested list to look like a folder tree. Now you can .

  13. Seamus says:

    …see it. http://moronicbajebus.com/playground/cssplay/explorer-list/
    Something went wrong in the post.

  14. Rahul says:

    I wanted the definition title and the definition description to display inline, so one after the other horizontally, maybe with some list-style-image between to seperate – but the point is that they should be on the same line. So far I’ve been able to remove the margins/padding so they line up vertically, but not horizontally. I tried all the combinations of display: inline on dd, dt and dl, but I guess I was missing something. And I already set list-style to none. :)

  15. Rahul,
    [displaying dt and dd inline]
    The ideal CSS2 solution would be:
    dt {display: run-in;}
    This works in Opera but not in Mozilla nor in IE (haven’t tested Safari). As a cross-browser workaround you could use:
    dt {float: left; margin-right: 0.5em;}
    … and maybe add some margin adjustments to dd as well.

  16. Rahul says:

    Ahh, float: left is what I was looking for.. great! Maybe this kind of thing is handy to document as well, since I’m sure a lot of people look for ways to format definition lists more accurately…
    Thanks, Andre. :)

  17. Victor says:

    Rahul, maybe something like the way I display the blogroll on the lower right corner of my blog?

  18. Rahul says:

    Yes Victor, something like that… I’m sure that with the right amount of work someone could make it look more or less exactly like Windows Explorer or such, while maintaining CSS and XHTML validity. It’d be a sweet deal, because I get my ears complained off by clients that must have it look exactly the same…

  19. although i know it’s very flawed (e.g. it doesn’t resize well if you change your font size dramatically), i’d love to hear what people think of this simple thing i slapped together in a few minutes:
    tree structure, explorer style
    the next step would be to add little icons (folder, document, etc), but that would probably involve adding extra classes to each list item…

  20. hmmm…after posting this, i saw that seamus did something very similar (and more elegant). oh well, worth a try though…

  21. Rahul says:

    I imagine it’s not hard to make such a tree; my point is that it’d be nice to see a tutorial like this available for those of us who aren’t as skilled or experienced with XHTML/CSS so that we might see some XHTML lists for these applications rather than endless repetitions of <img>&nbsp;<font>text</font><br> everywhere. :)

  22. I’m working with a nested list that acts not as a sitemap but rather as a left navigation… I’ve got a box-model hack from Zeldman, but I’m still getting a weird indentation problem in IE 5.0 for Windows.
    http://www.commonplacebook.com/testing/index.html
    http://www.commonplacebook.com/testing/pc_ie7.css
    All my other testing looks good. Any ideas what I’m doing wrong here?

  23. Rahul says:

    I don’t think you’re so much doing something wrong as overestimating IE5′s CSS rendering skills ;) Maybe that’s something worth documenting too?

  24. Danny says:

    This may be of interest – using a little script to make the lists expand/contract:
    http://dannyayers.com/archives/001961.html

  25. Ian Lloyd says:

    Thought I might share this with you – when I was re-working the Site Map for Nationwide.co.uk, I also went for the nested list approach with images in CSS used to denote structure. Doesn’t *look* like a list, but it surely is …
    http://www.nationwide.co.uk/sitemap.asp?s=home

  26. jim says:

    just as soon as I begin to forget … I come across this page. Looks like another night at the bar. Game 7 never happened. Game 7 never happened. Game 7 never happened. Game 7 never happened. Game 7 never happened.

  27. Chris says:

    Dan,
    Your articles are consistently high signal :: noise ratio – thank you!
    Any thoughts (semantically speaking) about using definition lists for site navigation (e.g. the Mozilla FireBird site http://texturizer.net/firebird/ ) vs. using nested unordered lists?

  28. Ryan says:

    chris–i’m with you on using dl’s for navigation. what it enables that ul’s may not is the flexibility to use second level elements when not every first level element contains second levels….did that make sense? i guess what i’m trying to say is that the dt tag does not have to contain a dd tag. so you could use your dt’s for ‘headers’ as the firebird site did or you could use them as level1 elements and use your dd’s for any sublevel elements which is a workaround for nesting (to a certain degree)
    rahul–i’ve used nested lists (dl’s and ol’s) to create a tree-list(of sorts) that expands when users click on an icon or it’s corresponding title. it uses a little bit of shareware javascript that switches the display property of the ol when the user clicks on the dl. so like many computer problems – there are all sorts of possibilities out there to achieve your windows list…

  29. Alderete says:

    I love this technique for site maps and site navigation. One thing I noticed when doing this on my own site is that, because I’m putting the site map in a sidebar, my horizontal space is limited. Most of the online examples I’ve found are more interested in simulating buttons by way of a {display:block}, etc. than the relatively simple styling example you have here.
    I prefer to keep the outline format, as you have, but this example stops short of adjusting the indentation, etc., which I also wanted to do.
    I was able to achieve 80% of what I wanted by adding one new rule (#sitemap ul { margin: 0; padding: 0; }), and one addition to one of your rules (#sitemap li ul { padding-left: 1.5em; }), but I would love to see more comprehensive treatment of the possibilities…
    Thanks for a nice example!

  30. Martin says:

    Rahul and Andre Leistner asked for the horizontal variant of the navigation. alistapart describes perfectly detailed how to do that. (Just add ‘display: inline;’ to ul and li!)
    Very usefull site, thank you!

  31. What’s the point in using background instead of list-style-image? I think that list-style-image is more appropriate in this case. If you use (background: url(bullet.gif) no-repeat 0 50%;) and an item is long enough that it breaks into two or more lines, that looks not so great.

  32. Andrew M says:

    Based on the original example above the background list images do not print in IE 6 and Safari 1 and I have “print background images and colors” selected in my browser settings. I swaped the background list style with the list-style-image Stepan mentions and the list images now print BUT I’ve lost most cotrol over aligning my list images. So it seems boths options have their drawbacks and unfortunately I have to go with what is printable over what looks better on screen but won’t print. Any other ideas? This is still a great tutorial!

  33. Mike P says:

    Recently, I tried to achieve an inline bullet list with background images for the bullets, like this:

    ul li {display: inline; padding: 0 0 0 2em; background: url(test.gif) no-repeat;}
    ...
    <ul>
    <li>Ipsum lorem dolor sit amet</li>
    <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec justo. Nam quis lorem. Nunc sem. Fusce hendrerit pretium ligula. Phasellus rhoncus malesuada libero. Aliquam fringilla lacus ac ligula. Quisque vel urna vitae urna semper semper. Sed laoreet orci fermentum sapien. Donec eleifend eros a pede. Cras quis sem ac nunc interdum bibendum. Morbi nec massa. Vivamus molestie metus eget quam. Aliquam erat volutpat. Ut odio. Donec iaculis metus eu ipsum. Mauris venenatis varius ipsum. Phasellus feugiat libero nec est. Nulla facilisi.</li>
    </ul>

    The problem lies in the longer li. Here, IE makes its background image bullet magically disappear, whereas NN and Mozilla seem not to have a problem with it.
    If anyone has a workaround for this, I’d love to hear about it, as it’s a real pain when you’re trying to do something flexible.

  34. Hot Project says:

    I have found nested ul to be very useful, however the visual style of the sub list indent is quite unappealing.
    To re-position my nested ul indent, I have found this works:
    ul li ul li {
    position:relative;
    left:-10px
    }
    It works on IE & Firefox, anyways…