In a previous post about using CSS to style HTML tables, I covered collapsing borders, empty cells, and the inline-table
display type. In this post I’ll cover headers and footers, captions, and columns, as well as other points which are good to know when using CSS with tables.
As with the previous post, the information in this post was derived the specifications for CSS 2.1 and various versions of HTML (HTML 4, XHTML 2, and HTML 5 are similar enough for this discussion).
Headers and footers
While most tables contain only data rows, you get flexibility if you use table headers (<thead>
) and footers (<tfoot>
). While it may seem odd, both the header and the footer must appear before any body rows. For this example:
Head 1 | Head 2 | Head 3 |
---|---|---|
Foot 1 | Foot 2 | Foot 3 |
R1C1 | R1C2 | R1C3 |
R2C1 | R2C2 | R2C3 |
R3C1 | R3C2 | R3C3 |
the HTML structure is roughly:
- <table>
- <thead></thead>
- <tfoot></tfoot>
- <tr></tr>
- etc.
- </table>
The reason that the header and footer need to come before the body rows is so they can both be printed if the table spans multiple pages when being printed. In the above example, a page break is forced between the last two lines, and doing a print preview (either with IE 8 or Firefox) whill show the header and footer repeated for the two halves of the table.
Another thing to point about about the example is it wraps the first two rows with <tbody></tbody>
tags. You can have as many of these tags in a table as you like, and you can mix them with rows which are direct descendants of the table. If you examine the table with a DOM inspector you’ll see that the third row gets an implicit tbody
block wrapped around it. This is true of all the major browsers.
Captions
- Caption position:
- text-align:
- Caption text:
The green border is to force margins above and below the caption/table combination to not collapse. It helps to be familiar with not only how margins collapse but the CSS Box Model in general when trying out this example.
All the browsers wrap the caption when it’s wider than the table. If you set the caption to not wrap, however, Safari and IE 7 will stretch the table’s width so the caption will fit, while the other browsers don’t change the table’s width to accommodate the length of the caption.
All four of the major, recent browsers treat margins differently:
- Firefox separates the margins of the table and caption, so adding margin to the top of the table or bottom of the caption will cause them to move away from each other. For the other browsers, adding a top margin to the table will affect spacing above the caption. Update 3/23/2011: As of version 4.0, Firefox acts like the other browsers, so adding margins to the table does not cause the caption to separate from the body of the table.
- Adding top and bottom margins to the caption on Safari seems to cause both margins to appear below the caption. This is most likely a bug.
- IE 8 adds top margins for the table and caption together.
Safari appears to have bug with how it renders the border of the table. If you change the caption to the bottom, you’ll notice a gap in the upper right corner. If you make the caption non-wrapping, put it on the bottom, make it short, then put it back on the top, you’ll see an artifact of the old border on the upper right. These glitches do not appear when the table cell has actual content (it’s empty for this example), or if you do not change the caption position dynamically. This appears to be fixed with the latest Webkit nightly build.
Columns
Using CSS with the <colgroup>
and <col>
tags allows you to work around the fact that HTML tables are row-centric. This example not only shows you how you can style a column, it also shows you the different table layers and how they are put together to render a table.
Beware that there are some functions of this example which do not correctly work for Firefox (at least through 3.0.9, the latest version as of this post). These issues are discussed at the end of this post.
- Red border for cols C, D:
Col A | Col B | Col C | Col D | |||
---|---|---|---|---|---|---|
Row 1 | A1 | B1 and C1 | B1 | C1 | D1 | |
Row 2 | A2 and B2 | A2 | B2 | C2 | D2 | |
Row 3 | A3 | B3 | C3 | D3 | D3 and D4 | |
Row 4 | A4 | B4 | C4 | C4 and C5 | D4 | |
Row 5 | A5 | B5 | C5 | D5 |
The CSS specification says that you can only style the border, background, width, and visibility of columns. For this particular table column B’s color can be changed. Also, column borders only show up if the table collapses borders; they will not appear if border-collaps
is not set to collapse
.
It’s important to remember that the columns are logical groupings. The individual cells are descendants of the table’s rows, but not of the columns. Because of this, you can’t specify particular cells of a column (e.g. col td
) and borders will be around the entire column, not the individual cells.
The last two columns are grouped together with <col span="2" />
, which is why on most of the browsers, the border wraps around the pair of columns instead of individual columns. Firefox wraps the individual columns.
Unlike the other browsers, Opera also shows the border separating the <thead>
block from the table’s body. It does the same if the table has a <tfoot>
section.
Other points
The table columns example demonstrates other points about styling tables with CSS, namely how to target spanning cells, how CSS considers the various parts of tables to be layered, and a couple issues with Firefox’s rendering of table borders and cell backgrounds.
Targeting spanning cells
When you style a particular cell or column, you need to be aware of how your presentation affects cells which span multiple rows or columns. Cells are considered parts of the leftmost column and the topmost row in which they appear.
In the example above, if you select the checkboxes which enable cell spanning, the background for row 4, and the background for column B, you can see this in action. The cell that represents B1/C1 inherits the background color of column B, but the cell representing A2/B2 does not. Likewise, the cell representing C4/C5 has the same background as the other cells in row 4, but the cell for D3/D4 does not.
CSS table layers
Because of how tables are structured in HTML, there are many opportunities for conflicting CSS definitions. For example, what happens if you give a row one background color and a column another color? The cell where the row and column intersect can only have one background.
The CSS 2.1 table specification has a useful diagram which shows that the various components of tables are assigned logical layers. In general, the more specific the object, the higher its precedence. Most of the layers are represented with differing background colors in this example, the exception being column groups. Working from the back (the layer with the lowest precedence) are the table itself (<table>
), column groups (<colgroup>
), columns (<col>
), row group (<tbody>
, <thead>
, and <tfoot>
), rows (<tr>
), and cells (<td>
and <th>
). Because of this layering, selecting the checkbox which sets the background color of cell B4 will override all other background colors.
Borders are also selected with the layers in mind, but only if the widths are the same. That’s why the 3px red border shows up around the two columns. If you select the 1px red border, it won’t show up unless you eliminate the cell borders; since the cells are at a higher layer, that border is used in favor of the column border.
The latest nightly Webkit build seems to have introduced a bug with the column border, causing it to not change when switch between 1px and 3px. If you toggle any other setting, however, the border will become correct. The latest release of Safari does not exhibit this problem.
There are actually other rules which govern which border shows up, as outlined in the CSS specification for table border conflict resolution. In addition to the border’s width and the border’s layer, the border’s style the cell’s position also affect which border is used.
If you look at the source for this document you’ll notice that there is no <tbody>
section; the rows are all direct descendants of the <table>
block. As mentioned above, all browsers will insert an implicit <tbody>
block around such rows. In fact, browsers will also allow you to use tbody
in your CSS, even though it’s not in your HTML. The CSS for this page does that.
Firefox table border and background issues
Firefox (at least as of 3.0.9) seems to have a rendering bug which causes the right column to have a couple of the borders be extra thick. The extra pixel-width appears sometimes at the bottom of the borders, sometimes at the bottom. There are times when more than one column has the extra thickness. In other cases the thicknesses are consistent but there’s a missing pixel, while there are some times when the borders look fine. It’s not clear to me what cases trigger this.
Background colors defined for rows are sometimes obscured by a column when dynamically changed. If you start with a fresh reload of this page (may need to hold down the shift key to get everything reset), enable the spanned cells, then enable the column color, you’ll notice that the right half of cell B1/C1 is not yellow. When I tried it with Firefox 3.0.9/Mac, switching away from that window was enough to get the right half of the cell to be yellow. Switching back to the window and disabling the column color clears the yellow except for the right half of B1/C1 (but it goes back to transparent when I switch again to a different window). This behavior does not happen when you try the same test with the row background.
Another Firefox issue is borders for both tables and the cells show up if defined in the CSS, but will not if the borders initially are not showing but you use Javascript to add the borders. either by changing object classes or changing the style of the object itself. Cell borders will correctly go away (by unchecking the cell border checkbox) but the column borders do not.
This last dynamic column border behavior seem to be fixed in the latest Firefox 3.1 beta, but the background color and border width issues still seem to occur.
Leave a Reply