Advanced Tables

July 2002 by Philipp Lenssen

Tables are often used -- or, one could say, misused -- for layouting a page. In this day and age, one can use CSS (Cascading Style Sheets) to do that job more elegantly; but yes, it's still not perfect due to a lack of browser support (take infamous Netscape 4, for instance). In the following tutorial however I will focus on tables to structure actual tabular data, as opposed to styling a page.

Tables to structure tabular data

A typical table, as intended by the W3C (the World Wide Web Consortium), is used for tabular data. Let's take a look at a simple table that marks-up personal data:

Personal data
Name Age Job
John Smith 28 Technical Consultant
HTML source:
<table>
    <caption>Personal data</caption>
    <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Job</th>
    </tr>
    <tr>
        <td>John Smith</td>
        <td>28</td>
        <td>Technical Consultant</td>
    </tr>
</table>
CSS source:
table
{
    border: 1px solid black;
    border-collapse: collapse;
}

th,
td
{
    padding: 6px;
    border: 1px solid black;
    text-align: left;
    vertical-align: bottom;
}

The CSS contained in the sample above is just a suggestion for a possible rendering -- stylesheets should be designed in a way to "spice up the content", but the structure is already provided in the HTML.

So how is the table structured? We got the following 5 basic elements:

Element relationships

But how does the browser know that td "John Smith" belongs to th "Name"? In this case, it seems to be obvious; but to strengthen the intended relation, we could add the following "scope" attribute:

HTML source:
<table>
    <caption>Personal data</caption>
    <tr>
        <th scope="col">Name</th>
        <th scope="col">Age</th>
        <th scope="col">Job</th>
    </tr>
    <tr>
        <td>John Smith</td>
        <td>28</td>
        <td>Technical Consultant</td>
    </tr>
</table>

Now, the scope of the th is set to col (for "column").

Breaking it up

If our table contains many more rows, it can become necessary to break it up in different subsections. For that, HTML provides a mechanism to add 3 elements right inside the table:

Why did I not list "tfoot" at the bottom? Well, that's because this is the actual order those elements have to appear inside a table. Let's take a look at how we would enhance our little sample table using above elements. I will add an "ID" to every person, which could be a unique identifier in a database. Also, the ID will now be a sub-header to each row.

Personal data
ID Name Age Job
9101 John Smith 28 Technical Consultant
1203 Mary Johnson 31 Customer Service
HTML source:
<table>
    <caption>Personal data</caption>
    <thead>
        <tr>
            <th scope="col">ID</th>
            <th scope="col">Name</th>
            <th scope="col">Age</th>
            <th scope="col">Job</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">9101</th>
            <td>John Smith</td>
            <td>28</td>
            <td>Technical Consultant</td>
        </tr>
        <tr>
            <th scope="row">1203</th>
            <td>Mary Johnson</td>
            <td>31</td>
            <td>Customer Service</td>
        </tr>
    </tbody>
</table>
CSS source:
thead th
{
    background-color: #eee;
    text-align: center;
}

th[scope="col"]
{
    padding-top: 16px;
    background-image: url(arrow_down.gif);
    background-repeat: no-repeat;
    background-position: 50% 100%;
    padding-bottom: 20px;
    border: 0;
}

th[scope="row"]
{
    padding-left: 16px;
    text-align: right;
    font-style: italic;
    background-image: url(arrow_right.gif);
    background-repeat: no-repeat;
    background-position: 100% 50%;
    padding-right: 20px;
    border: 0;
}

As you can see, we now used the "thead" element to differentiate the "th" color in the stylesheet. Also, we select every th with a scope="col" attribute, and every th with a scope="row" attribute seperately. This is advanced CSS selector syntax which unfortunately fails in some popular browsers, but the following image illustrates how it will display in Mozilla 1/ Netscape 6:

(However, the CSS degrades in a way that still makes it absolutely accessible. The basic structure of the table can still be rendered in any browser; and even, on other media than screen.)

Content of cells

Semantical data is beyond HTML tables; that is, what does this table cell actually mean when it contains "name", or "age"? For the time being, we can make our own classes that we can later on use to style the cells via CSS. I will now simply use a "td" of class="name" for every cell containing a person's name, and assign a background-image to those. The result might look like this:

Personal data
ID Name Age Job
9101 John Smith 28 Technical Consultant
1203 Mary Johnson 31 Customer Service
HTML source:
    ...
    <th scope="col" class="name">Name</th>
    ...
    <td class="name">John Smith</td>
    ...
CSS source:
td.name
{
    background-image: url(head.gif);
    background-repeat: no-repeat;
    background-position: 0 50%;
    padding-left: 20px;
}

Where to go from here

This was just a small overview, but you are encouraged to try out many more things yourself. For example, how to use alternate coloring for every second row. Also, the number one place to go to see what else you can do with tables (like summary, and colgroup) is the official W3C specification on tables.