Semantically Valid HTML5 Tables

Learning to code tables in HTML can be challenging. There are a lot of tags and attributes that are associated with tables. If your goal is to code tables semantically, a lot of these can help define the content of your tables. If you've been coding HTML for a while, you migth have missed some of the ways that we can make our code more meaningful for search engines and usability.

Basic Table Code

Tables are wrapped, of course with the HTML tag. The most basic kinds of tables also use TR tags to specify table rows and TD to specify table data (most of the time cols). Let's take a look at what a simple table would look like with these.

GIF PNG JPG SWF
Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

Here's the code for that

 
<table> 
	<tr> 
		<td></td> 
		<td>GIF</td> 
		<td>PNG</td> 
		<td>JPG</td> 
		<td>SWF</td> 
	</tr> 
	<tr> 
		<td>Compression</td> 
		<td>lossless</td> 
		<td>lossless</td> 
		<td>lossy</td> 
		<td>variable*</td> 
	</tr> 
	<tr> 
		<td>Max Colors</td> 
		<td>256 indexed</td> 
		<td>Trillions</td> 
		<td>Thousands</td> 
		<td>Thousands</td> 
	</tr> 
</table> 

Even in this unstyled version, human beings can probably tell that what the context of this table is. It's a list of online file formats with a row for the compression and a row for the maximum number of colors. For computers and search engines though, it's pretty fuzzy other than the fact that it is a table, there's no semantic (descriptive) data in the HTML. We'll fix that.

Adding a caption to the table

 
<table> 
	<caption>Online file format differences</caption>
	<tr> 
		<td></td> 
		<td>GIF</td> 
		<td>PNG</td> 
		<td>JPG</td> 
		<td>SWF</td> 
	</tr> 
	<tr> 
		<td>Compression</td> 
		<td>lossless</td> 
		<td>lossless</td> 
		<td>lossy</td> 
		<td>variable*</td> 
	</tr> 
	<tr> 
		<td>Max Colors</td> 
		<td>256 indexed</td> 
		<td>Trillions</td> 
		<td>Thousands</td> 
		<td>Thousands</td> 
	</tr> 
</table> 

Here's what that looks like

Online file format differences
GIF PNG JPG SWF
Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

The CAPTIONS tag is optional, but it explains the content of the table and is another excellent keyword placeholder for search engine optimization (SEO). You can treat the caption as a title or more of a visible description of your table.

THEAD & TBODY

This and most tables contain first row that is usually the header for all of the rows following below them. The THEAD tag allows you to define that as an area. In the same way, the TBODY tag lets you define one or more sections of your tables. Each of these can have a CLASS or an ID selector making this a powerful way to identify your tables for CSS.

This makes the code look like this:

  1. More semantically meaningful
  2. Easier to style with CSS separately from the rest of the table content

This won't make the table look any different, but the code will look like this:

 
<table> 
	<caption>Online file format differences</caption> 
	<thead>
		<tr> 
			<td></td> 
			<td>GIF</td> 
			<td>PNG</td> 
			<td>JPG</td> 
			<td>SWF</td> 
		</tr> 
	</thead>
	<tbody>
		<tr> 
			<td>Compression</td> 
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<td>Max Colors</td> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody>
</table> 

TFOOT

Where there's a header, there's probably a footer and HTML provides the TFOOT tag for this purpose. In this case, I can use this tag to define the area at the bottom of the table that will provide information about the peculiarities of the SWF format that I've placed a * symbol next to in the table.

 
<table description="This table provides a description of the differences between the different online graphic formats"> 
	<caption>Online file format differences</caption> 
	<thead> 
		<tr> 
			<td></td> 
			<td>GIF</td> 
			<td>PNG</td> 
			<td>JPG</td> 
			<td>SWF</td> 
		</tr> 
	</thead> 
	<tfoot> 
		<tr> 
			<td><p>* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.</p></td> 
		</tr> 
	</tfoot> 
	<tbody> 
		<tr> 
			<td>Compression</td> 
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<td>Max Colors</td> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody> 
</table> 

Here's what that looks like

Online file format differences
GIF PNG JPG SWF

* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.

Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

Strangely, the TFOOT tag needs to go after the THEAD tag and before the TBODY tag so the footer gets defined at the top of the table, but appears at the bottom...weird.

COLSPAN & ROWSPAN

If you look at the table above carefully, there's a problem. The cell that is wrapped by the TFOOT tag has only one TD cell, whereas all of the other TR tags have 5 TD cells. Therefore the browser thinks of all of the content there as a single TD and since it is first, assumes it belongs in the first col. Since it is the largest piece of content, it makes that col be as wide as necessary to contain that text and really messes up the formatting of your table.

What we want is to have the browser render the cell (TD) in the footer as if it spanned the width of all of those 5 cells. To do that, we'll use the COLSPAN attribute.

<table description="This table provides a description of the differences between the different online graphic formats"> 
	<caption>Online file format differences</caption> 
	<thead> 
		<tr> 
			<td></td> 
			<td>GIF</td> 
			<td>PNG</td> 
			<td>JPG</td> 
			<td>SWF</td> 
		</tr> 
	</thead> 
	<tfoot> 
		<tr> 
			<td colspan="5"><p>* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.</p></td> 
		</tr> 
	</tfoot> 
	<tbody> 
		<tr> 
			<td>Compression</td> 
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<td>Max Colors</td> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody> 
</table> 
Online file format differences
GIF PNG JPG SWF

* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.

Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

That looks a lot cleaner. In the same way, the ROWSPAN attribute would allow you to build cells that spanned a certain amount of vertical cols. That get's a little tricky to visualize and code, but it is possible

TH

Clearly, some of our information in the table are col or row headers. You can identify these with the TH tags. These replace the TD tags and again can be easily targeted with CSS since they will clearly mark things that are meant to be table headers. Since you've also added the THEAD and TFOOT tags, you can even format the col and row headers easily and separately with CSS selectors...yummy.

 <table description="This table provides a description of the differences between the different online graphic formats"> 
	<caption>Online file format differences</caption> 
	<thead> 
		<tr> 
			<td></td> 
			<th>GIF</th>
			<th>PNG</th>
			<th>JPG</th>
			<th>SWF</th>
		</tr> 
	</thead> 
	<tfoot> 
		<tr> 
			<td colspan="5"><p>* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.</p></td> 
		</tr> 
	</tfoot> 
	<tbody> 
		<tr> 
			<th>Compression</th>
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<th>Max Colors</th> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody> 
</table> 

This actually looks a little different since most browsers will style headers as bold:

Online file format differences
GIF PNG JPG SWF

* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.

Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

The SCOPE attribute

For an even more accurate definition of what the different TH tags describe, you can use the SCOPE attribute of the TH tag. It allows you to code wether the TH describes a ROW or a col which is much clearer. Like other things, it doesn't really affect how the table looks. Here's the code:

 
<table description="This table provides a description of the differences between the different online graphic formats"> 
	<caption>Online file format differences</caption> 
	<thead> 
		<tr> 
			<td></td> 
			<th scope="col">GIF</th> 
			<th scope="col">PNG</th> 
			<th scope="col">JPG</th> 
			<th scope="col">SWF</th> 
		</tr> 
	</thead> 
	<tfoot> 
		<tr> 
			<td colspan="5"><p>* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.</p></td> 
		</tr> 
	</tfoot> 
	<tbody> 
		<tr> 
			<th scope="row">Compression</th> 
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<th scope="row">Max Colors</th> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody> 
</table> 

This creates a table that more clearly identifies the different sections and purpose of it's parts. It's also very easy to code with CSS. In order to do that, we'll add a class to the table code and apply some CSS code.

 
<table class="mytable" description="This table provides a description of the differences between the different online graphic formats">
	<caption>Online file format differences</caption> 
	<thead> 
		<tr> 
			<td></td> 
			<th scope="col">GIF</th> 
			<th scope="col">PNG</th> 
			<th scope="col">JPG</th> 
			<th scope="col">SWF</th> 
		</tr> 
	</thead> 
	<tfoot> 
		<tr> 
			<td colspan="5"><p>* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.</p></td> 
		</tr> 
	</tfoot> 
	<tbody> 
		<tr> 
			<th scope="row">Compression</th> 
			<td>lossless</td> 
			<td>lossless</td> 
			<td>lossy</td> 
			<td>variable*</td> 
		</tr> 
		<tr> 
			<th scope="row">Max Colors</th> 
			<td>256 indexed</td> 
			<td>Trillions</td> 
			<td>Thousands</td> 
			<td>Thousands</td> 
		</tr> 
	</tbody> 
</table> 

Here's what the finished table looks like with the CSS assigned to it:

Online file format differences
GIF PNG JPG SWF

* The SWF format is a vector based format that can act as a container for other formats. Compression is inherited from other programs and can be customized.

Compression lossless lossless lossy variable*
Max Colors 256 indexed Trillions Thousands Thousands

And here's the CSS code I applied to it:

 
<style>
	.mytable {
		width:600px;
		font: 12px Arial;
		border-collapse:collapse;
	}
	
	.mytable thead th {
		background-color:#ADD8E6;
		border: 1px solid #888;
		color:#2F4F4F;
	}
	
	.mytable tbody th {
		background-color:#2F4F4F;
		color:#FFF;
		border: 1px solid #888;
		text-align:right;
	}
	
	.mytable tbody td {
		border-bottom:1px solid #888;
		border-right:1px solid #888;
	}
	
	.mytable caption {
		text-align:right;
		font-size:18px;
		font-weight:bold;
	}
	
	.mytable tfoot {
		background-color:#d4e6d9;
		border: 1px solid #d4e6d9;
	}
	
</style>	

There's nothing too remarkable about the CSS code, except that I was able to target every part of the table easily and clearly with simple selectors using a single class (mytable) to target every element in the table. What makes that possible is semantically clear HTML that uses these different tags to clearly describe the table to CSS.

blog comments powered by Disqus