Oli Warner About Contact Oli on Twitter Subscribe

CSS Table of Contents

Monday, 12 March 2007 css webdev

I bumped into Derek Punsalan’s 5ThirtyOne the other day and saw his take on a CSS version of a Table of Contents. It’s a good effort. That sounds harsh but don’t mean it like that — it’s just 80% of the way there…

So I put my thinking cap on and thought out a better method of doing it, with similar CSS impact and less HTML impact.

The <br /> tag he has at the end of his list items was the first thing that made me feel queezy — not helped by the use of the background image or the <ul> tag.

As I wrote yesterday, standards are here to make us use tags semantically and table of contents is probably as ordered a list as you can get so a <ul> shouldn’t be used.

So here’s my example. I’m going to show off a nested list that would be used to show sub-chapters. The same works with Derek’s code but you have to keep adding breaks at the end of each line.

CSS Table of Contents

The HTML for that:

<ol class="toc">
<li><span>Introduction</span> <a href="#">Page 1</a>
<ol>
<li><span>Subtitle 1</span> <a href="#">Page 1</a></li>
<li><span>Subtitle 2</span> <a href="#">Page 1</a></li>
</ol>
</li>
<li><span>Experiment</span> <a href="#">Page 2</a></li>
<li><span>Conclusion</span> <a href="#">Page 4</a></li>
<li><span>Discussion</span> <a href="#">Page 5</a></li>
</ol>

And we style that up with just 4 CSS rules. They’re longer than Derek’s but there you go.

ol.toc li {
clear: left;
border-bottom: dashed 1px #aaa;
height: 1.05em;
margin-top: 10px;
position: relative;
}

ol.toc a, ol.toc span {
background: #fff;
padding: 0 3px 0 0;
float: left;
position: absolute;
text-decoration: none;
}

ol.toc a {
padding: 0 0 0 3px;
right: 0;
}

ol.toc ol {
list-style: lower-roman;
margin: 1.5em 0 1em 5%;
padding: 0;
background:#fff;
float: left;
display: block;
width: 95%;
}

It’s not perfect. Internet Explorer support for subtitles is pretty dismal – just as with Derek’s. I really should leave links underlined and I’m not doing that here. You could argue that my method of positioning the lines so the borders intersect correctly or the width model I’m using is dodgy. I would probably agree on all fronts.

There is probably another method of doing all this that works a lot better. If you know it, please make sure to let me know in the comments.