October 19, 2003 · Dan Cederholm

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.