Designing Data Part 1: Table structure

The goal of this two-part article is to demonstrate how to create XHTML-compliant tables and how to style them effectively using CSS.

In Part 1, we tackle the basic structure of the table.

Part 1: Table Structure

The first step in any web page development is taking the data and marking it up using semantic and standards compliant XHTML. Let's start with a basic example that you've likely used before.

<table>
 <tr>
   <th>Year</th> <th>Quantity</th>
 </tr>
 <tr>
   <td>2003</td> <td>50</td>
 </tr>
 <tr>
   <td>2004</td> <td>100</td>
 </tr>
 <tr>
   <td>Total</td> <td>150</td>
 </tr>
 </table>

This is a simple four row table, with the cells in the first row being defined as header cells. Nothing too extraordinary but only the first step in putting our table together.

Next, we add some information about our table and then define our rows a little more.

<table>
 <caption>Total Sales of Thingamajigs</caption>
 <thead>
 <tr>
   <th>Year</th> <th>Quantity</th>
 </tr>
 </thead>
 <tfoot>
 <tr>
   <td>Total</td> <td>150</td>
 </tr>
 </tfoot>
 <tbody>
 <tr>
   <td>2003</td> <td>50</td>
 </tr>
 <tr>
   <td>2004</td> <td>100</td>
 </tr>
 </tbody>
 </table>

The caption element on the table helps describe the table and what its purpose is. The caption tag should be the first element after the table tag and is the title of the table. In most browsers, the caption will appear centered and on top of the table. In Part 2, we'll look at ways to change this.

We've also grouped the rows into three elements: THEAD, TFOOT and TBODY. But why is the tfoot BEFORE the tbody? This allows, for example, a user agent (aka: your browser) to display the header and footer of the table while it loads the body of the table in between.

Now that we've described our rows, it's time to describe our columns. There are two elements that accomplish this task: COLGROUP and COL. Let's modify our table again to include this extra information.

<table>
 <caption>Total Sales of Thingamajigs</caption>
 <colgroup>
 <col />
 <col />
 </colgroup>
 <thead>
 <tr>
   <th>Year</th> <th>Quantity</th>
 </tr>
 </thead>
 <tfoot>
 <tr>
   <td>Total</td> <td>150</td>
 </tr>
 </tfoot>
 <tbody>
 <tr>
   <td>2003</td> <td>50</td>
 </tr>
 <tr>
   <td>2004</td> <td>100</td>
 </tr>
 </tbody>
 </table>

We've indicated that our table contains one group of columns that has two columns.

Attributes

Now we tread into troubled waters. Theoretically, most of the attributes that I'm about to get into should be handled using CSS. However, due to browser support or conflicting CSS and HTML support for certain features, I'll proceed to cover them here.

Table Attributes: rules, frame, and border

The border attribute works just as it always has. Just specify a numeric value to indicate how many pixels wide it should be. The border will normally appear bevelled in most browsers unless overridden with CSS.

The frame attribute controls the display of the outer most border on the table. Possible values are void, above, below, hsides, vsides, lhs, rhs, box and border. void is the default value and will remove the border from around the table. Check out the W3C on how these attributes affect the table. How the border is drawn is different in all three browsers that I tested in. IE rendered a 3d border on all sides, Opera a solid black border, and Firefox a gray border on the left and top with black on the right and bottom. In IE, when a value other than void is specified, IE will incorrectly render a border on the cells inside the table as well. For example, if you specify lhs then the left side of each cell will get rendered. Firefox and Opera render this correctly.

The rules attribute has five easy attributes: none, groups, rows, cols, and all. If a value of none is specified then no lines will be drawn in between the cells. This is the default value. Interesting to note here is that if you do not specify a rules attribute, any border style (using CSS) that is set on your colgroup's or col's will not be used. But specify a value of none and suddenly the border style comes to life. A value of groups will apply a border (gray and bevelled in IE, 1px black in Firefox and Opera) around each thead, tfoot, tbody and colgroup. Setting to rows or cols will apply a border between each respectively. All will apply a border around every cell. Again, IE breaks from the pack and displays a border around the entire table when anything but none is specified and the frame attribute hasn't been set.

If you wish to use the frame or rules attributes, it's best to use them together.

Columns Attributes: span, align, valign and width

Our colgroup's and col's can have spanning assigned to them. This doesn't actually collapse multiple cells into one like the rowspan or colspan attributes on a cell. It simply allows for a short-hand way of specifying attributes across multiple columns.

<colgroup>
 <col />
 <col />
 </colgroup>
 <colgroup>
 <col />
 <col />
 <col />
 </colgroup>

...can also be written as...

<colgroup span="2" />
 <colgroup>
 <col span="2" />
 <col />
 </colgroup>

The span attribute on the colgroup indicates that the colgroup spans two columns. No col elements are used when a span attribute is present on a colgroup. If col elements do exist in a colgroup then the span attribute on the colgroup is ignored. The span attribute on the col element also indicates that there are two columns.

Next are the align and valign attributes. These can be applied to both the colgroup and col elements and work much like their cell-based versions. Setting align="right" on a column should set the text of every cell within that column to the right. These attributes are important as well because there is no CSS standard for using the text-align property on col or colgroup. Therefore, text alignment needs to be set at the HTML level. Unfortunately, Mozilla don't support the setting of align on a colgroup as of yet. IE does support text-align to be set at the CSS level even though it's not in the spec but best to stay with the HTML approach to keep things more forward compatible.

The width attribute can be specified using one of the three formats:
width="100" width in pixels
width="20%" width in percentage
width="2*" relative width indicating that the cell should be twice as wide as a regular cell. This relative sizing doesn't work in IE or Opera so I'd likely avoid it.

Also good to note is that using a percentage or relative width in IE expands the overall table to 100%, whereas in the versions of Mozilla and Opera that I tested in, it collapsed to the smallest area required to fill the cells — the expected behaviour.

In Part 2, we'll look to give this table a little more style using CSS.

Notes

Accessibility

There's another facet to creating your table structure that I haven't touched on here and that is accessibility. This is definitely a topic that needs to be covered on its own. Be sure to check out Table rendering by non-visual user agents and Tablin, a table linearization tool.

For More Information:

Browsers tested:

Update: It seems someone took the time to translate this into Russian. Many thanks!

Published June 08, 2004 · Updated September 17, 2005
Categorized as HTML and CSS
Short URL: https://snook.ca/s/164

Conversation

8 Comments · RSS feed
Eugene T.S. Wong said on August 02, 2004

I noticed that you said that relative sizing doesn't work in Opera, then you said that "it collapsed to the smallest area required to fill the cells $this->normalizeEntities16bit("8212") the expected behaviour.". What is "it"? Percentage?

--
Eugene T.S. Wong

Jonathan Snook said on August 02, 2004

To clarify, specifying a width (of any length) in Mozilla or Opera will not expand the width of the table to 100% of its container like it does in IE.

Relative widths (using the asterisk notation) is not supported in Opera.

akella said on August 04, 2004

to Update.
I'm glad you thanks for the translation.Your article is one of the best on this subject.I added some examples to first part(Visitors askes me for that).
I'll be happy if you find them useful.
Second one will go soon.

Susanna said on September 12, 2005

I'm glad I found your page. I tried using HTML to set alignment for a column instead of CSS. It made no difference in IE - worked either way. But it still doesn't work in Mozilla, not even Moz 1.7 which supposedly supports HTML columns.

charm said on November 18, 2005

wow this page is so innovative!

Mike Smullin said on June 01, 2006

Very nice. Thanks for clearing this up with a few simple examples.

[..] Currently you can only achieve this effect in all browsers with tables--but it's different now in XHTML 1.0 Strict than it was in HTML 4.01 Traditional. [..]

Mag said on August 29, 2006

We will appreciate more examples.

Zeley Iu said on February 27, 2007

Green peace, blue sky

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.