Marking up tables
Posted Aug 14, 2004 at 12:13 AM
Once upon a time, someone discovered that if you added a border=”0” to a table tag in HTML, you could remove the cell borders, and use tables for laying out web pages. The poor old table tag and its children have lived in infamy since. With today’s browsers, tables are still fine to use, provided you use them for their original intent: presenting tabular data. This post discusses various aspects of the table to consider before applying it to a specific markup problem.
The table problem
As we look towards a web standards driven development philosophy, we really need to look at our historical reliance on the table tag. Especially around cases where we rely on tables for layout, rather than actually representing tabular data.
Why are tables bad?
- Rendering complexity, especially in terms of nested tables so commonly found when tables are used for layout. This can greatly increase the time it takes a browser to render your page to your user, sometimes considerably so.
- Page weight considerations, especially since they are often littered with presentational attributes and tags.
Should a table be used? A framework for deciding
There’s all kinds of data on our pages, and it helps to have a framework for thinking about this data as we decide how to best represent it. In some cases, tables are appropriate, but often times, headings or lists can accomplish the same things in much better, lighter, faster and more predictable ways. Again, once we have consistency in the markup we’ll use, we can make CSS presentation decisions as necessary. What follows is a start to such a framework of thinking.
Could headings be used instead?
Headings are useful when you are presenting single pieces of data that gives other data a reference point.
Headings typically define lists of content or data. They can be extremely valuable in situations where the name identifies the purpose of the data, such as on product data sheets or individual personnel records.
When the name contained in the heading is used to identify the content or data (or the purpose of the content or data), headings are a good approach.
Could (un)ordered lists be used instead?
Ordered and unordered lists are useful when presenting data with a single dimension of information.
If the name is clearly the strongest part of the name/value pair, it might make sense to simply have the name as the sole dimension, use an unordered list, and identify the name and data with separate tags within the list, if required.
This should only be used if it is obvious that the name stands out as the important data point. If the name and value compete for importance, I would choose another option.
Would definition lists be better?
Definition lists are useful when presenting lists of single units of data with explanatory or subsidiary information.
This is ideal for situations where the name’s purpose is identified by the value, such as when defining the purposes of keywords used in a certain parameter.
Typically, when the value is used to identify the name’s purpose, definition lists can help.
If you got this far…
Tables are useful when presenting data with two dimensions of information.
One consideration is to use tables for name-value pairs that also have headings. Although a name-value pair typically has a single dimension of data, if the name has one heading, and the value has another, then you have defined two dimensions of data, and can use a table. In other words, a table is the right decision when the intention is to define a grid of data—the first dimension is down the grid, defining a number of rows, while the second dimension is across the grid, defining a number of attributes of each row.
Getting tables right: An evolution from a bad table to a good one
So we have decided to use tables when we want to represent tabular data. Ok, now how can we ensure that the diverse and relentless stampede of users, browsers and devices interpret our intent correctly? In the same way as they do with non-tabular data on our pages—by using markup that’s focused not on presentation, but rather on a semantically meaningful structure for the data.
We’ll start with a typical table that represents movie show times. It’s small, easy to understand and explain, and illustrative of a case where we may use tables.
<h3>Movie Show Times</h3><table cellpadding="2" border="0" width="100%"><tr><td width="100%" align="center"><b>Movie</b></td><td align="center"><b>Show Times</b></td></tr><tr><td width="100%">The Village</td><td nowrap="nowrap">7:00 PM, 9:00 PM</td></tr><tr><td width="100%">The Shining</td><td nowrap="nowrap">6:45 PM, 10:00 PM</td></tr></table>- Download this code: /code/table_01.html
First, let’s remove things related to presentation, because we no longer desire to bloat our markup with meaningless presentation information, since we’ll rely on CSS for that. This removes over 170 characters from this small example, and gets us to the following:
<h3>Movie Show Times</h3><table><tr><td>Movie</td><td>Show Times</td></tr><tr><td>The Village</td><td>7:00 PM, 9:00 PM</td></tr><tr><td>The Shining</td><td>6:45 PM, 10:00 PM</td></tr></table>- Download this code: /code/table_02.html
Unfortunately, this still isn’t valid XHTML Strict markup, so we need to make some more changes.
<table summary="A chart of movie show times by title."><caption>Movie Show Times</caption><thead><tr><th>Movie</th><th>Show Times</th></tr></thead><tbody><tr><td>The Village</td><td>7:00 PM, 9:00 PM</td></tr><tr><td>The Shining</td><td>6:45 PM, 10:00 PM</td></tr></tbody></table>- Download this code: /code/table_03.html
Here’s what we’ve done:
- We’ve moved the title from a heading tag to a caption tag. Caption tags are required for XHTML tables, immediately following the table’s opening tag. They usually hold the table’s title or an explanation of the nature of the table. Visual browsers will usually place the caption centered and above the table, but of course, we can change this default appearance with CSS. Non-visual browsers use the caption to explain the table to the user.
- We’ve added a summary attribute to the table tag. This is also required, and especially handy for users using non-visual means to read the information. It provides additional context for the data they’re about to read.
- We’ve clarified our intent that the first row of the table is a header row for the body of the table by adding thead and tbody tags and changing some of our td tags to th tags. Our use of thead and tbody (and optionally, tfoot) tags enables user agents to support the scrolling of table bodies independently of the table header and footer. Additionally, for printing, we have the ability to repeat the table’s header and footer on each page. Clearly stating our intent with valid semantics delivers a lot of flexibility. Note: when used, thead and tfoof tags must be rendered before the tbody tag so that browsers and devices can load the body of the table first.
- Our use of th tags eliminates the need for extra presentational markup such as bold tags and align attributes to suggest that these are headers, because we use the correct semantic markup to indicate precisely that this is our intent. Visual browsers will usually render th tags bold and centered, but again, we can use CSS to change this default behavior.
- Additionally, because we now have two types of tags defining cells (td for data cells and th for heading cells) we can later style them uniquely without any work or additional style hooks. The same applies to our thead, tbody and tfoot tags—using them give us convenient hooks for styling later on.
Finally, if we want to be really accessible, we should associate the headings with the cells themselves. Doing this allows screen readers to read the first row of data as “Movie: The Village, Show Times: 7:00 PM, 9:00 PM”. Here’s how:
<table summary="A chart of movie show times by title."><caption>Movie Show Times</caption><thead><tr><th id="movie">Movie</th><th id="showtime" abbr="Plays">Show Times</th></tr></thead><tbody><tr><td headers="movie">The Village</td><td headers="showtime">7:00 PM, 9:00 PM</td></tr><tr><td headers="movie">The Shining</td><td headers="showtime">6:45 PM, 10:00 PM</td></tr></tbody></table>- Download this code: /code/table_04.html
We’ve also used the abbr attribute on one of the th tags to allow the screen reader to read the shorter “Plays” over “Show Times” text as the table is read.
Characteristics of good tables
Having gone through the above transformation from a bad to good table, we can use this as another framework for determining whether or not to use a table. Given the lessons learned, we can also say that a good table possesses ALL of these characteristics:
- The table tag includes the summary attribute and no other.
- The table contains a caption tag.
- The table uses thead and tbody, and optionally, tfoot.
- The table uses th for heading cells, and uses the id attribute on th tags for relating headers to data cells.
- Optionally, shorter versions of the column heading text is defined by using the abbr attribute on the th tag.
- The table uses td tags for data cells, and uses the headers attribute on these tags for relating headers to data cells.
- The table’s heading and data cells do not contain presentational markup or attributes.
- Generally, the table itself sets an id attribute for unique style and behavior binding.
If this is not the case, alternative approaches need to be considered.
Styling tables: tips and options
Define things like borders, padding, spacing, widths, colors, alignment, etc. in CSS, not HTML. To create a grid with borders, there are several options:
- Define bottom and right borders on the cells, and top and left borders on the table, thead, tbody or tfoot.
- Alternatively, just define borders for the cells, and define border-collapse: collapse on the table.
- Take advantage of id’s associated with th cells to define different small logo leads for an interesting appearance.
Pivoting tables
I came across this table the other day, and thought we should look into it a little. Note that the heading cells are not in a thead, nor are the in the first row. Instead, they are in the first column. Not much else to say, just found it interesting.
<table summary="A chart of movie show times by title."><caption>Movie Show Times</caption><tr><th>First Name</th><td>Dan</td></tr><tr><th>Last Name</th><td>Boerner</td></tr><tr><th>Company</th><td>Microsoft</td></tr></table>- Download this code: /code/table_05.html
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 14, 2004. Those would be good places to start looking for related posts.
This post is closed to new comments.