A blog post from danboe.net

Marking up lists

Posted Aug 9, 2004 at 12:17 AM

Why make lists so hard? They’re all over our pages, and they’re all over the web. Web pages would not be the same without the categorized lists of text and links that make up navigation, headline summaries, RSS feeds, headers, footers, etc. They’re the bricks and mortar of home pages and portals, and the freeways between deeper, more content-focused pages. They’re a pretty obvious thing, and they should be pretty simple to represent. Indeed, they can be, but pick a few lists from a few pages and look at their HTML implementation. You will find a diverse collection of bloated and inconsistent representations. Why? Because we still implement them from a perspective of how we desire them to look, instead of from a knowledge of the consistent components that fundamentally are.

Because we use them so often, they’re all over our pages. Because we’re so driven by the visual requirements, they’re much heavier than they need to be, and they are implemented in far too many different ways (in terms of markup). This adds cost: for the bits sent across the wire; for the development, documentation, testing and reuse of them, and for the styling of them. I assert that this is no longer necessary, and recommend we stop to consolidate the implementations to a very small number and move forward.

All the lists we’ll ever need

Implementing lists consistently allows us to control their appearance across devices, browsers and platforms in predictable and manageable ways. It allows us to significantly reduce page weight across our pages. It also implies a schema or contract for the markup they will be implemented as, which is of vital importance for styling flexibility and adding behavior to them. Such a schema also helps us validate the instances as we create them, and test them quickly. It allows them to be rendered extremely efficiently as well.

I assert that all of these special-cases we have for lists are no longer needed, and can be replaced with standard XHTML implementations of unordered lists, ordered lists, and definition lists.

But the proof, as they say, is in the pudding. What follows is a discussion of lists across some pages that are not implemented as such, contrasted with an implementation that uses one of the standard lists.

Before and after example: hard line breaks in navigation

Here’s an example of a list from the left side bar on the MSN home page:

The intent here seems simple enough: to provide a list of navigational links, with a desire for item in the list to be on its own line. Here’s the HTML implementation (indentation added for readability) of this list:

  1. <div class="hd">
  2. <h4>
  3. <b>
  4. Going Places
  5. </b>
  6. </h4>
  7. </div>
  8. <div class="ct">
  9. <a href="#">Air Tickets</a>
  10. <br />
  11. <a href="#">City Guides</a>
  12. <br />
  13. <a href="#">Hotel Deals</a>
  14. <br />
  15. <a href="#">Local Traffic</a>
  16. <br />
  17. <a href="#">Maps &amp; Directions</a>
  18. <br />
  19. </div>
  20. Download this code: /code/lists_01.html

Why is this implementation bad?

The items themselves are just free-form text. This creates two problems:

  1. We rely on classes for style hooks (“hd” and “ct”), adding page weight, especially as it multiplies out since the classes repeatedly applied across similar modules on the page.
  2. The markup infers no rules defining the flow of text, and we struggle to fight the default behavior in this type of implementation. When the text is forced to wrap before our explicit breaks (as can happen from the introduction of lengthy content, from moving the content to a smaller container or from users using different font sizes), the resulting display can become confusing. It becomes hard to determine where one item ends and the next begins. In other words, this implementation doesn’t take into account the fluid nature of web pages that will always remain outside of our control.

Additionally,

  • There’s a container for the h4 tag that seems to serve no purpose that the h4 itself could not. Additionally, it’s given a class attribute that adds weight.
  • The use of the br tag is not semantic (it doesn’t apply meaning to the page); it’s presentational.
  • Likewise, so is the b tag inside of the h4 tag, which, by the way is actually deprecated in XHTML.
  • There’s no containing element for this list and label (or header and container) to denote that they are related. We’re so concerned with the style of the header and container (probably because of a Photoshop file) that we’ve forgotten the most important aspect of them—that they’re related to each other. We intend for “Going Places” to be interpreted as the label for this list of links, even though the markup does nothing to identify this intent.
  • The links are contained within a div tag, which, like span, is defined by the W3C as a generic container that has no default semantic meaning, and therefore does not come with any default rendering or styling applied to it by user agents. This is especially problematic for users accessing the site via old browsers, text browsers, devices or adaptive technology. Using a div or span should always be a last resort, because by default, it will appear as if it does not exist.

Wouldn’t it be nice to indicate that these are in fact part of a list? We’ll get there.

Here’s a better implementation:

  1. <div id="goingplaces">
  2. <h4>Going Places</h4>
  3. <ul>
  4. <li><a href="#">Air Tickets</a></li>
  5. <li><a href="#">City Guides</a></li>
  6. <li><a href="#">Hotel Deals</a></li>
  7. <li><a href="#">Local Traffic</a></li>
  8. <li><a href="#">Maps &amp; Directions</a></li>
  9. </ul>
  10. </div>
  11. Download this code: /code/lists_02.html

So why is this better?

  • It’s valid XHTML, and semantically relevant. There are no presentational tags, yet all browsers will render it just fine. Even browsers without CSS will be able to view this content in manners that make sense by default, as a clearly organized and contained list of items that are related to each other. Because the markup implies meaning (a list) all browsers can best decide how to render it, even without our receiving or supporting our desired style guidelines. Different devices will make appropriate rendering choices based on each device’s capabilities.
  • It has an appropriate structure that can be utilized for hooking style rules too. Want red text? No bullets? Numbered list instead? No problem. Horizontal list separated by bars? Yes, that too. All without changing the HTML.
  • It is explicitly identified so that it can be styled uniquely from other such lists of links in the page, such as “Look It Up,” “Shop,” or “Living.” Of course, this is optional, assuming that there’s a containing element for the container, as there is in the “leftbar” div here. Having just leftbar allows us to target #leftbar h4 and #leftbar ul, having both leftbar and goingplaces allows us to target goingplaces uniquely.

Side note: even better?

Individual modules of markup are usually determined by their data source and need for independence. If we look at the left side of the msn.com page, should it clearly be one or several modules? If we thought for a moment about a one module approach, we could make the markup even lighter and semantically better by marking it up like so:

  1. <ul>
  2. <li>
  3. <h4>Previous Module</h4>
  4. <ul>
  5. <li>Previous Module Links</li>
  6. </ul>
  7. </li>
  8. <li>
  9. <h4>Going Places</h4>
  10. <ul>
  11. <li><a href="#">Air Tickets</a></li>
  12. <li><a href="#">City Guides</a></li>
  13. <li><a href="#">Hotel Deals</a></li>
  14. <li><a href="#">Local Traffic</a></li>
  15. <li><a href="#">Maps &amp; Directions</a></li>
  16. </ul>
  17. </li>
  18. <li>
  19. <h4>Next Module</h4>
  20. <ul>
  21. <li>Next Module Links</li>
  22. </ul>
  23. </li>
  24. </ul>
  25. Download this code: /code/lists_03.html

Of course, such an approach would have the following requirements:

  • Each individual section is a part of the whole, not independent. So “Going Places” could move up or down within the module, but not outside of its current container, since it would always be a part of the rest, and would “come with” it wherever it is rendered.
  • The rendering appearance of each section of the whole is similar.

Before and after example: horizontal list 1

Here’s another list of links, this time the Big 6 network links from the header of http://womencentral.msn.com/.

The intent here is obviously have a horizontally orientated, pipe-delimited list of links. Here’s the HTML for this implementation:

  1. &nbsp;&nbsp;
  2. <a href="#">MSN Home</a>
  3. &nbsp;&nbsp;|&nbsp;&nbsp;
  4. <a href="#">My MSN</a>
  5. &nbsp;&nbsp;|&nbsp;&nbsp;
  6. <a href="#">Hotmail</a>
  7. &nbsp;&nbsp;|&nbsp;&nbsp;
  8. <a href="#">Shopping</a>
  9. &nbsp;&nbsp;|&nbsp;&nbsp;
  10. <a href="#">Money</a>
  11. &nbsp;&nbsp;|&nbsp;&nbsp;
  12. <a href="#">People &amp; Chat</a>
  13. Download this code: /code/lists_04.html

Why is this implementation bad?

  • We’re adding content for presentational purposes! Have you ever searched the internet for ”|” or ”&nbsp;”? Who would? Why clutter our content with it?
  • Some devices, platforms or older browsers will actually render &nbsp; as a visible character instead of a non-breaking space, confusing the user experience by placing garbage in the content.
  • The use of a non-breaking space prevents the content from wrapping. If the container is too small for the content (for example, if the big 6 becomes the big 9) browsers will interpret our intent to be “never let this content wrap,” and will usually break other visual rules we request (especially regarding widths) to obey our request, flawed as it is.

Here’s a better implementation:

  1. <ul id="big6">
  2. <li class="first"><a href="#">MSN Home</a></li>
  3. <li><a href="#">My MSN</a></li>
  4. <li><a href="#">Hotmail</a></li>
  5. <li><a href="#">Shopping</a></li>
  6. <li><a href="#">Money</a></li>
  7. <li><a href="#">People &amp; Chat</a></li>
  8. </ul>
  9. Download this code: /code/lists_05.html

Why is this better?

  • We’ve clarified content by removing content that had only presentational meaning and removed problems associated with the display of &nbsp;.
  • We’ve used standard markup that browsers have a consistent default rendering for.
  • We’ve used markup that allows us to target style rules at.
  • We can move the presentation to CSS (and get the exact same visual results) with style rules like the following:
  1. #big6 li
  2. {
  3. border-left: 1px solid #fff;
  4. display: inline;
  5. padding-left: 20px;
  6. padding-right: 20px;
  7. }
  8.  
  9. #big6 li.first
  10. {
  11. border-left: none;
  12. padding-left: 0;
  13. }
  14. Download this code: /code/lists_01.css

Before and after example: horizontal list 2

Here’s another section of the MSN home page, a simple bulleted list of links. It’s important to point out at this point that by default, a ul tag will bullet each item in the list. Here’s the HTML:

  1. <table cellpadding="0" cellspacing="0" border="0" class="ql">
  2. <tr>
  3. <td class="md">
  4. <div>
  5. &#x20;
  6. <a href="#">Insurance</a>
  7. &#x20;
  8. <b class="dot">&middot;</b>
  9. &#x20;
  10. <a href="#">Loans</a>
  11. &#x20;
  12. <b class="dot">&middot;</b>
  13. &#x20;
  14. <a href="#">News</a>
  15. &#x20;
  16. <b class="dot">&middot;</b>
  17. &#x20;
  18. <a href="#">Markets</a>
  19. &#x20;
  20. <b class="dot">&middot;</b>
  21. &#x20;
  22. <a href="#">Credit Report</a>
  23. &#x20;
  24. </div>
  25. </td>
  26. </tr>
  27. </table>
  28. Download this code: /code/lists_06.html

Why is this bad?

  • Once again, we’ve littered the content with &nbsp; (or its equivalent &x20;) and &middot; to represent a bullet. This is not content—it’s presentation.
  • We’ve used deprecated tags such as the bold tag for presentation. This does not belong in markup, it belongs in the style sheet.
  • We’ve containing the list in a meaningless div, and surrounding that with an even more meaningless table which is apparently only there for coloring to be applied against.

Here’s a better implementation:

  1. <ul>
  2. <li class="first"><a href="#">Insurance</a></li>
  3. <li><a href="#">Loans</a></li>
  4. <li><a href="#">News</a></li>
  5. <li><a href="#">Markets</a></li>
  6. <li><a href="#">Credit Report</a></li>
  7. </ul>
  8. Download this code: /code/lists_07.html

Why is this better? For many of the same reasons as the previous example.

Before and After Example: Big 4

Another example is the equivalent set of primary links on the MSN home page, often referred to as the Big 4. The visual presentation might suggest that it’s different, but it’s really just another list of links. It does look different from what we expect in an unordered list, and it is certainly marked up differently today. Here’s the HTML:

  1. <div class="big4">
  2. <table border="0" cellpadding="0" width="90%" class="bt">
  3. <tr valign="middle">
  4. <td valign="top" class="lt">
  5. <img src="#" />
  6. </td>
  7. <td class="bgl" width="25%">
  8. <span>
  9. <a href="#">
  10. <img src="#" />
  11. </a>
  12. <br />
  13. <h4>
  14. <a href="#">My MSN</a>
  15. </h4>
  16. </span>
  17. </td>
  18. <td class="bgs" width="25%">
  19. <a href="#">
  20. <img src="#" />
  21. </a>
  22. <br />
  23. <h4>
  24. <a href="#">Hotmail</a>
  25. </h4>
  26. </td>
  27. <td class="bgs" width="25%">
  28. <a href="#">
  29. <img src="#" />
  30. </a>
  31. <br />
  32. <h4>
  33. <a href="#">Messenger</a>
  34. </h4>
  35. </td>
  36. <td class="bgr" width="25%">
  37. <span>
  38. <a href="#">
  39. <img src="#" />
  40. </a>
  41. <br />
  42. <h4>
  43. <a href="#">
  44. <b>Toolbar</b>
  45. </a>
  46. </h4>
  47. </span>
  48. </td>
  49. <td valign="top" class="rt">
  50. <img src="#" />
  51. </td>
  52. </tr>
  53. </table>
  54. </div>
  55. Download this code: /code/lists_08.html

Here’s a better approach. Seeing a pattern to the solutions yet?

  1. <div class="big4">
  2. <ul>
  3. <li>
  4. <a id="big4a" href="#">My MSN</a>
  5. </li>
  6. <li>
  7. <a id="big4b" href="#">Hotmail</a>
  8. </li>
  9. <li>
  10. <a id="big4c" href="#">Messenger</a>
  11. </li>
  12. <li>
  13. <a id="big4d" href="#">Toolbar</a>
  14. </li>
  15. </ul>
  16. </div>
  17. Download this code: /code/lists_09.html

Let’s consider the changes necessary to get here:

  • We removed the table completely and all of the extra weight that went along with it, including the two extra cells that only existed for appearance.
  • The original implementation used 2 sets of links per item—1 for the image and 1 for the text. That’s just silly, so we removed the image links and the images entirely from the markup. They’re not vital semantic information, they’re presentational, and we can move this same presentation entirely to CSS. Really? Sure, we can provide “desired style rules” for visual browsers to render the li tags as follows:
  • Without the default bullet associated with unordered lists, since we don’t want one here.
  • Render li tags inline instead of block, so they appear horizontally instead of vertically.
  • We can set width, margin and padding to give them a certain size.
  • Now here’s the trick (not a hack, just a good use of style as style was intended)

We can set a top padding for the li tags to give space for the image as a background image. Since we’ve given each li tag a unique id, we can easily set a different image for each link.

Of course, there is a very faint shaded image around this region on the page—but there’s really no reason why this could not be incorporated into the link images themselves, additionally saving us 3 image round trips (for the left, stretching middle and right images).

  • In addition to reducing the weight and burden to render, this is also now semantically structured and completely accessible regardless of browser, platform or device. Additionally, it’s more meaningful, because we don’t repeat the links to the destinations twice (as we were doing with image and text links that read the same text twice).
  • We removed the bold and br tags, since they’re presentational in nature. We removed the span tags because they have no apprarent semantic meaning.
  • We removed the heading (h4) tags, since it’s at best unclear as to what they’re headings for. Another interesting note is that the MSN home page does not have any h1, h2 or h3 tags. Only h4. Headings should be used to outline the page into a hierarchy of content, and it should always start at h1 (usually the page title) and work in succession from h1 through to h6 (if there are in fact 6 levels of meaning). Blindly starting from and restricting to h4 has no purpose whatsoever.

Before and after example: site navigation

Site navigation also suffers from similar problems. Consider the site navigation residing at http://tech.msn.com/howto/. Pretty straight forward navigation, with a highlight of what section you’re in. Here’s the HTML:

  1. <div class="nav">
  2. <table width="120" cellpadding="0" border="0" class="vnav">
  3. <tr>
  4. <td>
  5. &nbsp;<img src="#" />
  6. </td>
  7. <td>
  8. <a href="#">Home</a>
  9. </td>
  10. </tr>
  11. <tr>
  12. <td>
  13. &nbsp;<img src="#" />
  14. </td>
  15. <td>
  16. <a href="#">Product Reviews</a>
  17. </td>
  18. </tr>
  19. <tr>
  20. <td>
  21. &nbsp;<img src="#" />
  22. </td>
  23. <td>
  24. <a href="#">Downloads &amp; Tools</a>
  25. </td>
  26. </tr>
  27. <tr class="hilight">
  28. <td>
  29. &nbsp;<img src="#" />
  30. </td>
  31. <td>
  32. <a href="#">How-To</a>
  33. </td>
  34. </tr>
  35. <tr>
  36. <td>
  37. &nbsp;<img src="#" />
  38. </td>
  39. <td>
  40. <a href="#">News &amp; Trends</a>
  41. </td>
  42. </tr>
  43. <tr>
  44. <td>
  45. &nbsp;<img src="#" />
  46. </td>
  47. <td>
  48. <a href="#">Mobile</a>
  49. </td>
  50. </tr>
  51. <tr>
  52. <td>
  53. &nbsp;<img src="#" />
  54. </td>
  55. <td>
  56. <a href="#">Virus &amp; Security</a>
  57. </td>
  58. </tr>
  59. <tr>
  60. <td>
  61. &nbsp;<img src="#" />
  62. </td>
  63. <td>
  64. <a href="#">Games</a>
  65. </td>
  66. </tr>
  67. <tr>
  68. <td>
  69. &nbsp;<img src="#" />
  70. </td>
  71. <td>
  72. <a href="#">Business &amp; IT</a>
  73. </td>
  74. </tr>
  75. <tr>
  76. <td>
  77. &nbsp;<img src="#" />
  78. </td>
  79. <td>
  80. <a href="#">Shopping</a>
  81. </td>
  82. </tr>
  83. </table>
  84. <p class="Space">&nbsp;</p>
  85. </div>
  86.  
  87. Download this code: /code/lists_10.html

Whew, that’s a lot of HTML. However, at a structural level, site navigation is simply always just a list of links to other areas of the site. And the above does not indicate that it’s a list. A table is used for presentational reasons, not because the data is actually tabular. So really, all that’s needed for navigation markup is this:

  1. <ul id="nav">
  2. <li><a id="navhome" href="#">Home</a></li>
  3. <li><a id="navproduct" href="#">Product Reviews</a></li>
  4. <li><a id="navdownload" href="#">Downloads &amp; Tools</a></li>
  5. <li><a id="navhowto" href="#">How-To</a></li>
  6. <li><a id="navnews" href="#">News &amp; Trends</a></li>
  7. <li><a id="navmobile" href="#">Mobile</a></li>
  8. <li><a id="navvirus" href="#">Virus &amp; Security</a></li>
  9. <li><a id="navgame" href="#">Games</a></li>
  10. <li><a id="navbusiness" href="#">Business &amp; IT</a></li>
  11. <li><a id="navshop" href="#">Shopping</a></li>
  12. </ul>
  13. Download this code: /code/lists_11.html

Now that’s a big savings! We simply replaced the table with a list, removed the div tag and moved the id=”nav” to the ul tag, since site navigation is, by definition, always going to be a list of links. It’s a lot faster for the server to deliver and the browser to render. Of course, this will look and behave the same as it does today, assuming that it’s rendered with CSS along the lines of this:

  1. #nav ul
  2. {
  3. padding: 0;
  4. margin-bottom: 1em;
  5. }
  6.  
  7. #nav li
  8. {
  9. border: 1px solid #ccc;
  10. padding-left: 1.5em;
  11. }
  12.  
  13. #nav li a {
  14. color: #00f;
  15. }
  16.  
  17. #nav li a:hover
  18. {
  19. color: #f00;
  20. }
  21. Download this code: /code/lists_02.css

But wait, you say—the current approach highlights the section of the site we’re currently on. Yes, that too can be moved to CSS. Instead of having to determine which row gets the highlight class, we can stop conditionalizing the HTML for the navigation and instead set an ID value on the body that defines the type of page we’re on (home, product, download, etc.) and leverage the cascade provided by CSS to visually distinguish the section like this:

  1. #home #navhome,
  2. #product #navproduct,
  3. #download #navproduct
  4. {
  5. /* highlight rules go here */
  6. }
  7. Download this code: /code/lists_03.css

Finally, it’s important to stress that we’ve also changed from a generic HTML schema to a semantic one that the browser can understand. Even without getting our desired style guidelines for the navigation area, the browser knows that our intent is to provide a list of links that belong together and will render it in a predictable and reasonable way (as an organized, bulleted list). Not too shabby.

Doesn’t this limit the designer?

The answer is absolutely not! Once you have a page with good HTML structure, you can use CSS to create all the visual effects you want. As this these examples have demonstrated, a simple list can be transformed into just about anything with Cascading Style Sheets (CSS).

When to Use OL instead of UL

It should be evident that OL should be used when the intent is to actually identify a sequence where the automatic numbering that comes along with it is desired.

What have we learned here?

Use the semantic HTML tags for their intended purposes whenever possible. Take into consideration the default (no style applied) rendering of the markup before determining what markup to use. This helps make the markup more accessible.

  • Use HTML lists for content that is actually intended to be a list. Reduce the hundreds of implementations around lists in your code to one standard set of markup. This is much easier to develop, test, and style. Additionally, it’s much easier for the browser to understand and render, even in cases where our desired visual style guidelines (CSS files) are not requested or not supported.
  • Avoid using classes and the page weight that they have a tendency to create.
  • Avoid using div and span tags except as a last resort to establish generic semantic meaning of containment, relationship or association.
  • Stop using   and characters such as ”|” for presentational purposes.
  • Stop using presentational tags such as br, b and i. Instead, use em and strong
  • Don’t create repetitive links.
  • Don’t create images in markup unless they are actually valid to the content being delivered. Use CSS for applying images that are presentational or design oriented in nature.
  • Don’t use tables simply for reasons of presentation or layout.
  • Use heading tags to outline the and suggest a hierarchy of importance to the content in page.

Whitespace in list markup

There’s a bug to be aware of if you’re working a lot with lists. In Internet Explorer, even version 6, lists may be rendered with gaps in between items or nested lists when there is whitespace within the markup. I do not know of a solution, other than to remove all of the extra spaces, tabs and line breaks. If you know of an alternate solution, please comment.


This post is closed to new comments.

About this page

This page contains a single post from Daniel Boerner's blog, of which Boot Camp + Windows Vista = no more Airport Extreme reboots is the latest post.

Are there more posts like this one?

Possibly. Within this blog, this post is categorized under webdev and it was posted on August 9, 2004. Those would be good places to start looking for related posts.

Next post (newer)

Previous post (older)