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:
Name | Age | Job |
---|---|---|
John Smith | 28 | Technical Consultant |
<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>
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:
- table: the table element that contains all table data
- caption: the table caption that titles the table
- tr: a single table row
- th: a table cell heading
- td: a normal table cell
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:
<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:
- theader: the table header section
- tfoot: the table footer section
- tbody: the main table body section
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.
ID | Name | Age | Job |
---|---|---|---|
9101 | John Smith | 28 | Technical Consultant |
1203 | Mary Johnson | 31 | Customer Service |
<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>
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:
ID | Name | Age | Job |
---|---|---|---|
9101 | John Smith | 28 | Technical Consultant |
1203 | Mary Johnson | 31 | Customer Service |
...
<th scope="col" class="name">Name</th>
...
<td class="name">John Smith</td>
...
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.