Last week, we discussed table basics for the year 2010 (as opposed to 1995). We set up a simple semantic table with a caption, header and footer. Today, we’re going to go over two lesser-known elements: the colgroup
and col
elements. I had grand plans of going into some little-known attributes for other table elements, but we’ll leave that to next week.
So, my columns feel left out
In the last article, you saw how thead
, tfoot
and tbody
allowed for groupings of rows in a table. But often times, it’s useful to group columns as well. A couple uses I can think of include highlighting a totals column or perhaps a sales option that you want to promote. Other uses include the ability to set explicit widths for individual columns without much extra markup.
So, where do these elements go? When using column and column-group elements, you place the tags after the caption but before any row-groups or rows in the table. Modern user agents will then determine which cells belong to the appropriate column or column-group.
<table>
<caption>Elements To Use in Proper Tables</caption>
<colgroup span="2" width="100px">
<col width="90px" />
<col class="attribs" />
</colgroup>
<colgroup span="1" width="0*"></colgroup>
<thead>
...
colgroup
: grouping columns
As you may have guessed by the “group” part of the element name, colgroup
designates a structural grouping of columns. Semantically, you’re saying that the columns are related somehow.
col
: sharing attributes without structural grouping
Unlike colgroup
, col
does not specify structure, it merely allows you to share attributes across multiple columns. In fact, for purists, one might argue that col is purely layout-driven. I’ll let you judge of that on your own.
Only two attributes?
The use of colgroup
and col
in HTML is limited to two attributes: span
and width
.
Span
specifies the number of columns the group encompasses for colgroup
or the attribute should apply to in the case of col
. When using these two elements, make sure that the number of elements and their span
attributes don’t equal more than the number of cells you have per row.
Width
allows you to set the width of a column or columns in a column-group. When used in colgroup
elements, remember that it specifies width of each column in the group not the total width of the grouping. If a child col
also has width
set it will override the parent colgroup
setting. General width values are accepted, but there’s also a strange format available: the zero-asterisk (0*) value, which sets each column to be the minimum width needed to display the full cell content. You can also use an asterisk with a numerical value to designate proportional widths. For instance, if you want three columns to be set up proportionally, you could designate them as such:
<colgroup span="2" width="100px"></colgroup>
<colgroup span="3">
<colgroup width="1*" />
<colgroup width="4*" />
<colgroup width="2*" />
</colgroup>
<thead>
...
That structure would take the total remaining width after assigning 100px to the first two columns, divide it into seven portions (1+4+2 = 7), and then apply the correct width based on portion width multiplied by number of designated portions.
Beyond these two attributes, you can use most common attributes such as id
, class
, align
, etc.
Tell me about styling.
Here’s the drawback: colgroup
and col
have limited styling. You can only use four CSS attributes, and even they are limited:
background
: you can set a background, but it is only honored if both the row and cell backgrounds are transparent.border
: borders work if the table has borders set to collapse (border-collapse: collapse;
), at which point the borders appear based on the border conflict algorithm. If the table is set to have separated borders, no dice.width
: works as expected, no explicit limitations.visibility
: will only work with thecollapse
value.
But despite the limitations, these two elements can come in handy for informative tables. Let’s put it together with our table code from last time:
<table id="elements-for-tables">
<caption>Elements To Use in Proper Tables</caption>
<colgroup span="2" width="100px">
<col width="90px" />
<col class="attribs" />
</colgroup>
<colgroup span="1"></colgroup>
<thead>
<tr>
<th>Tag </th> <th>Attributes</th> <th>Description</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">* denotes optional child elements</td>
</tr>
</tfoot>
<tbody>
<tr>
<th>caption*</th>
<td>common attributes</td>
<td>A succinct description or title for the table.</td>
</tr>
...
</tbody>
</table>
table {
margin: 1em auto;
border-collapse: collapse; /* note that this is required for using border on columns */
}
caption { font-size: 1.2em; }
th, td {
padding: .25em;
border: 1px solid #000;
font-family: sans-serif;
}
caption, th {
color: #004900;
font-weight: bold;
text-align: left;
}
thead tr, tfoot tr { background-color: #aaa; }
thead th {
border-bottom: 3px double #000;
background-color: #ccc;
text-align: center;
}
tfoot td {
border-top: 3px double #000;
color: #333;
font-style: italic;
font-size: .8em;
text-align: right;
}
tbody th { color: #000; }
col.attribs {
background-color: #B6FFBD;
border: 2px dotted #004900;
}
The result:
Tag | Attributes‡ | Description |
---|---|---|
* denotes optional child elements | ||
† denotes tags to be discussed in part two, next week. | ||
‡ only tag-specific attributes are included. In general common attributes are also allowed. See the W3C HTML 4.01 Attribute Table for a complete list. | ||
caption* | A succinct description or title for the table. | |
colgroup* | span, width | A way to group columns for semantic accessibility, progressive enhancement and styling. |
col* | span, width | A child element of colgroup, used to share attributes amongst multiple columns. |
thead* | A group of rows comprising a header for the table. | |
tfoot* | A group of rows comprising a footer for the table. | |
tbody* | A group of rows comprising the body of the table. There can be multiple tbody elements. | |
tr | A table row. If thead, tfoot, and tbody are not used, this will be a child element of the table, otherwise it is a child element of the rowgrouping elements. | |
th* | †abbr, axis, colspan, headers, rowspan, scope | A table heading. A child element of tr. Most commonly used to signify column headings when used in a thead element, but can be used as a row heading as well. |
td | †abbr, axis, colspan, headers, rowspan, scope, | Table data. A child element of tr. The most numerous element in a table, it contains data. |
Notice the funky border collapsing in the footer and that the heading background color overrides the column background color. But don’t let that limit you: be creative, and you can accomplish great feats.
Just think of how that could be useful in extremely large data sets, accounting tables, or product tables. The possibilities are endless. Next week, we’ll discuss attributes galore for semantic, accessible table creation.
I have a question about the width of col/colgroups. I set up a table with a few cols of fixed width and one floating (to take up the rest of the space).
This works quite well, but I also have padding in my table cells. The problem is that Firefox (3.6.4) includes the padding in the column width calculation where IE (7,8) does not.
So on a [col width="100px"] applied to a [td style="padding:15px"], FF will render a cell where the contents have 70px. IE will reserve all 100px for the cell content, with the full padded width coming to 130px.
Is there something I can do to force both to conform short of ditching col/colgroup entirely and tagging individual cells?
**Incidentally, nifty trick with those asterisk units in cell width. I'll remember that one.
Michael,
I'm stumped. It's like the box-model issue all over again, except that had nothing to do with tables.
My preliminary answer is "IE sucks, again." (In other words, browser rendering issue, can't really be helped).
The rest of the Internet doesn't seem to have much advice either, when I went searching. I've never actually had this issue, but to be fair, I've never dev'd a project that really needed pixel-perfectly-equal columns across browsers.
Do you mind providing a link to a test page (or the live page) to give a better idea of other code it could be interacting with to cause this?