The layout of tables can get quite complicated, especially because CSS defines two different ways to calculate table and cell widths, as well as two ways to handle the borders of tables and elements internal to the table. Figure 1-4 illustrates the components of a table.
In general, a table is laid out according to the following principles:
Each row box encompasses a single row of grid cells. All of the row boxes in a table fill the table from top to bottom in the order they occur in the source document. Thus, the table contains as many grid rows as there are row elements.
A row group’s box encompasses the same grid cells as the row boxes that it contains.
A column box encompasses one or more columns of grid cells. Column boxes are placed next to each other in the order they occur. The first column box is on the left for left-to-right languages and on the right for right-to-left languages.
A column group’s box encompasses the same grid cells as the column boxes that it contains.
Although cells may span several rows or columns, CSS does not define how that happens. It is instead left to the document language to define spanning. Each spanned cell is a rectangular box one or more grid cells wide and high. The top row of this rectangle is in the row that is parent to the cell. The cell’s rectangle must be as far to the left as possible in left-to-right languages, but it may not overlap any other cell box. It must also be to the right of all cells in the same row that are earlier in the source document in a left-to-right language. In right-to-left languages, a spanned cell must be as far to the right as possible without overlapping other cells and must be to the left of all cells in the same row that come after it in the document source.
A cell’s box cannot extend beyond the last row box of a table or row group. If the table structure causes this condition, the cell must be shortened until it fits within the table or row group that encloses it.
The fixed-layout model is fast because its layout doesn’t depend on the contents
of table cells; it’s driven by the
width values of the table, columns, and cells
within the first row of the table. The fixed-layout model uses the
following simple steps:
Any column element whose
width property has a value other than
auto sets the width for that
If a column has an
width, but the cell in the first row of the table within that column
width other than
auto, that cell sets the width for that
column. If the cell spans multiple columns, the width is divided
equally among the columns.
Any columns that are still auto-sized are sized so that their widths are as equal as possible.
At that point, the width of the table is set to be either the
width for the table or the
sum of the column widths, whichever is greater. If the table turns out
to be wider than the column widths, the difference is divided by the
number of columns and added to each of them.
The automatic-layout model, although not as fast as the fixed-layout, is likely to be
much more familiar to authors because it’s substantially the same model
that HTML tables have used for years. In most current user agents, use
of this model will be triggered by a table with a
auto, regardless of the value of
table-layout—although this is not
The details of the model can be expressed in the following steps:
For each cell in a column, calculate both the minimum and maximum cell width.
Determine the minimum width required to display the content.
In determining the minimum content width, the content can flow to
any number of lines, but it may not stick out of the cell’s box. If
the cell has a
width value that
is larger than the minimum possible width, the minimum cell width is
set to the value of
width. If the
width value is
auto, the minimum cell width is set to the
minimum content width.
For the maximum width, determine the width required to display
the content without any line-breaking, other than that forced by
explicit line-breaking (e.g., due to the
<br> element). That value is the
maximum cell width.
For each column, calculate both the minimum and maximum column width.
The column’s minimum width is determined by the largest
minimum cell width of the cells within the column. If the column
has been given an explicit
width value that is larger than any of
the minimum cell widths within the column, the minimum column
width is set to the value of
For the maximum width, take the largest maximum cell width
of the cells within the column. If the column has been given an
width value that is
larger than any of the
maximum cell widths within the column, the maximum column width
is set to the value of
These two behaviors recreate the traditional HTML table behavior
of forcibly expanding any column to be as wide as its widest
In cases where a cell spans more than one column, the sum of the minimum column widths must be equal to the minimum cell width for the spanning cell. Similarly, the sum of the maximum column widths must equal the spanning cell’s maximum width. User agents should divide any changes in column widths equally among the spanned columns.
In addition, the user agent must take into account that when a
column width has a percentage value for its
width, the percentage is calculated in
relation to the width of the table—even though that width is not known
yet. The user agent must hang on to the percentage value and use it in
the next part of the algorithm. Once the user agent has determined how
wide or narrow each column can be, it can calculate the width of the
table. This happens as follows:
If the computed width of the table is not
auto, the computed table width is compared
to the sum of all the column widths plus any borders and
cell-spacing. (Columns with percentage widths are likely calculated
at this time.) The larger of the two values is the final width of
the table. If the table’s computed width is larger than the sum of
the column widths, borders, and cell-spacing, all columns are
increased in width by an equal amount so they fill the computed
width of the table.
If the computed width of the table is
auto, the final width of the table is
determined by summing up the column widths, borders, and
cell-spacing. This means the table will be only as wide as needed to
display its content, just as with traditional HTML tables. Any
columns with percentage widths use that percentage as a constraint,
but it is a constraint that a user agent does not have to
Table elements cannot have any padding, although they can have margins. Thus, there is never separation between the border around the outside of the table and its outermost cells.
Borders can be applied to cells, rows, row groups, columns,
and column groups. The
element itself can, as always, have a border.
There is never any separation between cell borders. In fact, borders collapse into each other where they adjoin so that only one of the collapsing borders is actually drawn. This is somewhat akin to margin-collapsing, where the largest margin wins. When cell borders collapse, the “most interesting” border wins.
Once they are collapsed, the borders between cells are centered on the hypothetical grid lines between the cells.
When two or more borders are adjacent, they collapse into each other, as shown in Figure 1-5. There are strict rules governing which borders will win and which will not:
If one of the collapsing borders has a
hidden, it takes precedence over
all other collapsing borders: all borders at this location are
If one of the collapsing borders has a
none, it takes the lowest priority.
There will be no border drawn at this location only if all of the
borders meeting at this location have a value of
none. Note that
none is the default value for
If at least one of the collapsing borders has a value other
hidden, narrow borders lose out to wider
ones. If two or more of the collapsing borders have the same
width, the border style is taken in the following order, from most
preferred to least:
inset. Thus, if two borders with the
same width collapse and one is
dashed while the other is
outset, the border at that location will
If collapsing borders have the same style and width but differ in color, the color used is taken from an element in the following list, from most preferred to least: cell, row, row group, column, column group, table. Thus, if the borders of a cell and a column—identical in every way except color—collapse, the cell’s border color (and style and width) will be used. If the collapsing borders come from the same type of element—such as two row borders with the same style and width, but different colors—the one farthest to the left and top wins in left-to-right languages; in right-to-left languages, the cell farthest to the right and top wins.
If any of the cells are baseline-aligned, the row’s baseline is determined and the content of the baseline-aligned cells is placed.
Any top-aligned cell has its content placed. The row now has a provisional height, which is defined by the lowest cell bottom of the cells that have already had their content placed.
If any remaining cells are middle- or bottom-aligned, and the content height is taller than the provisional row height, the height of the row is increased by lowering the baseline in order to enclose the tallest of those cells.