4 notes &
Simulating colspan with CSS in a fluid layout, Part 1
This is the first of a five-part series of posts that detail my adventures in trying to achieve a colspan effect with the elements of a CSS layout. The posts follow this rough outline:
- table trouble
- script solutions
- opera issues
- subpixel issues
- conclusions
Introduction
An HTML table element is used to define a tabular structure, whereas a CSS table display is used to define a tabular layout. Other CSS techniques (stacked, floated elements of equal width, for example) also imitate a tabular layout to some degree. This separation of structure and layout conceptually allows a tabular layout to be applied even to non-tabular content for the purpose of visual presentation.

tabular layout
Extending a table cell to occupy more than one column/row of a tabular structure is easy to achieve: The colspan/rowspan attributes of the HTML th/td elements handle this concisely. However, extending a table cell to occupy more than one column/row of a tabular layout of a non-tabular structure is daunting.

tabular layout with spanned cells
Additionally, I require that the rendered widths of two cells in the same row to be equal at the pixel level if their specified widths (expressed as a percentage) are equal. The aspect ratio of equal-width cells in the same row may be preserved by the fluid layout. Such cells would have different heights as a result of different widths, and a height discrepancy is likely to be more noticeable.
In this sequence of posts, I will describe a technique to extend an element across more than one column of a tabular layout while satisfying the above constraint. I will intimate a bit of my discovery process and address some browser compatibility issues. I will conclude by calling bollocks on the whole thing, and argue why you should use HTML tables for layout. (Hint: It’s not quite what you think.)
Don’t you know that colspan is inherently structural?
The CSS 2.1 specification on tables describes a table simply as a “rectangular grid of cells”. It has this to say with respect to cells:
Although CSS 2.1 does not define how the number of spanned rows or columns is determined, a user agent may have special knowledge about the source document; a future update of CSS may provide a way to express this knowledge in CSS syntax.
In other words, CSS currently provides no mechanism to specify that a cell spans more than one column or row (or, alternatively, that an element spans more than one cell). A browser must determine this from the HTML. Further, this again from the specification:
A “missing cell” is a cell in the row/column grid that is not occupied by an element or pseudo-element. Missing cells are rendered as if an anonymous table-cell box occupied their position in the grid.
So, not only does CSS provide no mechanism to specify that a cell spans more than one column or row, but a gap in a table display will be filled by a new box, rather than by extending the box of an existing cell in the same row or column.

tabular layout with a missing cell
This means that CSS alone cannot be used to specify the spanning of a cell of a table display, whether explicitly or (in what would be special cases) implicitly.
Yes, colspan is inherently structural. Moreover, the only way HTML provides to specify such structure is with the colspan attribute of a th/td element, which implies an HTML table. When I reference colspan in the context of a tabular layout, though, I’m not talking about table cells or even tables. I’m talking about controlling the horizontal and vertical alignment of the rectangular components of a visual presentation. I’m talking about a grid layout or a template layout, not a table per se. A template layout would be preferable, but template layouts are not supported by browsers as of this writing (unless you count the excellent jQuery plugin from Alexis Deveria).
Why not use an HTML table?
As mentioned above, an HTML table is used to define a tabular structure. That is, an HTML table defines content as tabular content. Using an HTML table to apply a tabular layout to non-tabular content is popularly considered an anti-pattern of web design. Tableless web layout is the accepted standard. Ask about it on a Q&A forum if you want to toast some virtual marshmallows.
Why not use a CSS table?
As mentioned above, CSS cannot be used to specify that an element spans more than one cell. The effect when attempting to do so depends on the table layout algorithm.
When explicitly specifying the width of each cell in a fixed table layout, the width of each column is determined by the width of the corresponding non-visible column element, or by the width of the corresponding cell in the first row. The width of each cell in each subsequent row is effectively ignored. In the following example, the elements in cells A, B, C, and D each has a width of 33.33%, the element in cell E has a width of 66.66%, and the element in cell G has a width of 99.99%.

fixed table layout
with wider cells in 2nd and 3rd rows
Despite having larger specified widths, elements E and G are truncated because the width of the respective column is determined by the width of the corresponding element in the first row.
When explicitly specifying the width of each cell in an automatic table layout, the width of each column is determined by the maximum of the width of the corresponding non-visible column element and, for each row, the width of the corresponding cell. So, the widest cell of a column effectively dictates the width of the column, to the degree that the cumulative width of the columns can be satisfied by the constraining width of the table. The following example shows a possible rendering of the same CSS table above, using an automatic table layout rather than a fixed table layout.

automatic table layout
with wider cells in 2nd and 3rd rows
The element in cell G has a width of 99.99%, so the first column occupies most of the width of the table. The other columns are visible only as slivers, though they might not be visible at all, depending on borders, padding, and the overall width of the table.
Regardless of the table layout, a single CSS table won’t work. But what about multiple CSS tables stacked on top of each other? If each row becomes its own table, not only can each row have a different number of columns, but the width of a cell can be set without influencing the widths of other cells in the same “column”.
Here we run into two more problems. The first problem is what the table layout algorithm does with leftover width. To illustrate, I finally present some code.
<div class="Table">
<div class="TableRow">
<div class="TableCell" id="a"></div>
<div class="TableCell" id="b"></div>
</div>
</div>
This structure will be styled as a CSS table that contains a single row, which has two cells.
.Table {
display: table;
width: 100%;
background-color: #FF00FF;
}
.TableRow {
display: table-row;
}
.TableCell {
display: table-cell;
height: 5em;
width: 25%;
}
#a {
background-color: #FF0000;
}
#b {
background-color: #0000FF;
}
[Incidentally, the TableRow element and its corresponding style are unnecessary here, since the CSS table model will automatically create an anonymous table row. It is included for the purpose of illustration.]
Each of the two cells is specified to occupy 25% of the width of the table, leaving 50% of the width unoccupied. You might expect to see 25% red, 25% blue, and 50% fuchsia.

expected table layout with leftover width
Instead, you would actually see 50% red and 50% blue.

actual table layout with leftover width
Both table layouts require that leftover width be distributed over the columns, with some fuzziness as to the nature of the distribution. So, regardless of how the widths of the cells are specified, the columns will together occupy 100% of the width of the table. Not even max-width:25% will help. Worse, browsers have slightly different strategies for distributing the leftover width, and those strategies cannot be controlled.
The conceptual solution is to specify the widths of the cells such that their cumulative width is 100% of the table, leaving no leftover width. When the percentages don’t add to 100%, a padding cell can be added to make up the difference. For example, given three cells, each with a width of 33.33%, a padding cell with a width of 0.01% could be added to the end of the row.
By a mathematical accident, this may actually work for a table with a small number (3, say) of relatively wide columns. It may appear to work in the general case, until you look closely at the table while resizing the window. Eventually, you will see a misalignment.

table layout pixel-level misalignment
The misalignment is due to some combination of the distribution of leftover width and the second problem with stacked tables, subpixel rounding. If the specified width of a cell is 50% of the width of the table, and the computed width of the table is an odd number of pixels, is the computed width of the cell rounded up or down? I’ll address subpixel rounding more in part 4.
Regardless, not only can the cells of the faux columns be misaligned as a result, but columns that have the same conceptual width may have different rendered widths. In the above example, suppose the width of the table was a number of pixels not divisible by 3. Since the three, supposedly equal-width columns must occupy 100% of the width of the table (or 99.99% of the width of the table with a 0.01% padding cell), one column will necessarily be wider or narrower by one pixel. This violates the constraint that the rendered widths of two cells in the same row must be equal at the pixel level if their specified widths are equal.
So, HTML tables are out, and CSS tables are out. In part 2 I’ll discuss layout alternatives and the options for sizing a spanned element using JavaScript.