18 Tables

Contents

18.1 Introduction to tables

Tables represent relationships between data. Authors specify these relationships in the document language and specify their presentation in CSS, in two ways: visually and aurally.

Authors may specify the visual rendering of a table as a rectangular grid of cells. Rows and columns of cells may be organized into row groups and column groups. Rows, columns, row groups, row columns, and cells may have borders drawn around them (there are two border models in CSS2). Authors may align data vertically or horizontally within a cell and align data in all cells of a row or column.

Authors may also specify the aural rendering of a table; how headers and data will be spoken. In the document language, authors may label cells and groups of cells so that when rendered aurally, cell headers are spoken before cell data. In effect, this "serializes" the table: users browsing the table aurally hear a sequence of headers followed by data.

Here is a simple three-row, three-column table described in HTML 4.0:

<TABLE>
<CAPTION>This is a simple 3x3 table</CAPTION>
<TR id="row1">
   <TH>Header 1      <TD>Cell 1        <TD>Cell 2
<TR id="row2">
   <TH>Header 2      <TD>Cell 3        <TD>Cell 4
<TR id="row3">
   <TH>Header 3      <TD>Cell 5        <TD>Cell 6
</TABLE>

This code creates one table (the TABLE element), three rows (the TR elements), three header cells (the TH elements), and six data cells (the TD elements). Note that the three columns of this example are specified implicitly: there are as many columns in the table as required by header and data cells.

The following CSS rule centers the text horizontally in the header cells and present the data with a bold font weight:

TH { text-align: center; font-weight: bold }

The next rules align the text of the header cells on their baseline and vertically centers the text in each data cell:

TH { vertical-align: baseline }
TD { vertical-align: middle }

The next rules specify that the top row will be surrounded by a 3px solid blue border and each of the other rows will be surrounded by a 1px solid black border:

TABLE { border-spacing: none }
TR#row1 { border-top: 3px solid blue }
TR#row2 { border-top: 1px solid black }
TR#row3 { border-top: 1px solid black }

Note, however, that the borders around the rows overlap where the rows meet. What color (black or blue) and thickness (1px or 3px) will the border between row1 and row2 be? We discuss this in the section on border conflict resolution.

The following rule puts the table caption above the table:

CAPTION { caption-side: top }

Finally, the following rule specifies that, when rendered aurally, each row of data is to be spoken as a "Header, Data, Data":

TH { speak-header: once }

For instance, the first row would be spoken "Header1 Cell1 Cell2". On the other hand, with the following rule:

TH { speak-header: always }

it would be spoken "Header1 Cell1 Header1 Cell2".

The preceding example shows how CSS works with HTML 4.0 elements; in HTML 4.0, the semantics of the various table elements (TABLE, CAPTION, THEAD, TBODY, TFOOT, COL, COLGROUP, TH, and TD) are well-defined. In other document languages (such as XML applications), there may not be pre-defined table elements. Therefore, CSS2 allows authors to "map" document language elements to table elements via the 'display' property. For example, the following rule makes the FOO element act like an HTML TABLE element and the BAR element act like a CAPTION element:

FOO { display : table }
BAR { display : table-caption }

We discuss the various table elements in the following section. In this specification, the term table element refers to any element involved in the creation of a table. An "internal" table element is one that produces a row, row group, column, column group, or cell.

18.2 The CSS table model

The CSS table model is based on the HTML 4.0 table model, in which the structure of a table closely parallels the visual layout of the table. In this model, a table consists of an optional caption and any number of rows of cells. The table model is said to be "row primary" since authors specify rows, not columns, explicitly in the document language. Columns are derived once all the rows have been specified -- the first cell of each row belongs to the first column, the second to the second column, etc.). Rows and columns may be grouped structurally and this grouping reflected in presentation (e.g., a border may be drawn around a group of rows).

Thus, the table model consists of tables, captions, rows, row groups, columns, column groups, and cells.

The CSS model does not require that the document language include elements that correspond to each of these components. For document languages (such as XML applications) that do not have pre-defined table elements, authors must map document language elements to table elements; this is done with the 'display' property. The following 'display' values assign table semantics to an arbitrary element:

table (In HTML: TABLE)
Specifies that an element defines a block-level table: it is a rectangular block that participates in a block formatting context.
inline-table (In HTML: TABLE)
Specifies that an element defines an inline-level table: it is a rectangular block that participates in an inline formatting context).
table-row (In HTML: TR)
Specifies that an element is a row of cells.
table-row-group (In HTML: TBODY)
Specifies that an element groups one or more rows.
table-header-group (In HTML: THEAD)
Like 'table-row-group', but for visual rendering, the row group is always displayed before all other rows and rowgroups and after any top captions.
table-footer-group (In HTML: TFOOT)
Like 'table-row-group', but for visual rendering, the row group is always displayed after all other rows and rowgroups and before any bottom captions.
table-column (In HTML: COL)
Specifies that an element describes a column of cells.
table-column-group (In HTML: COLGROUP)
Specifies that an element groups one or more columns.
table-cell (In HTML: TD, TH)
Specifies that an element represents a table cell.
table-caption (In HTML: CAPTION)
Specifies a caption for the table.

Elements with 'display' set to 'table-column' or 'table-column-group' are not rendered (exactly as if they had 'display: none'), but they are useful, because they may have attributes which induce a certain style for the columns they represent.

The default style sheet for HTML 4.0 in the appendix illustrates the use of these values for HTML 4.0:

TABLE    { display: table }
TR       { display: table-row }
THEAD    { display: table-header-group }
TBODY    { display: table-row-group }
TFOOT    { display: table-footer-group }
COL      { display: table-column }
COLGROUP { display: table-column-group }
TD, TH   { display: table-cell }
CAPTION  { display: table-caption }

User agents may ignore these 'display' property values for HTML documents, since authors should not alter an element's expected behavior.

18.2.1 Anonymous table boxes

Document languages other than HTML may not contain all the elements in the CSS2 table model. In these cases, the "missing" elements must be assumed in order for the table model to work. The missing elements generate anonymous boxes according to the following rules:

  1. Any table element will automatically generate necessary table boxes around itself, consisting of at least three nested boxes corresponding to a 'table'/'inline-table' element, a 'table-row' element, and a 'table-cell' element.
  2. If the parent of a 'table-cell' is not a 'table-row', a 'table-row' element will be assumed as its parent, and this element will generate an anonymous box that spans all consecutive 'table-cell' siblings.
  3. If the parent of a 'table-row' is not a 'table', 'inline-table', or 'row-group' element, the 'table-row' will be assumed to have a parent 'table' element that generates a box spanning all consecutive siblings also requiring a 'table' parent.
  4. If the parent of a 'table-row-group' is not a 'table' or 'inline-table', the 'table-row-group' will be assumed to have a parent 'table' element that generates a box spanning all consecutive siblings also requiring a 'table' parent.
  5. 'table-cell' elements are inserted as children of a 'table-row' element to contain consecutive children that are not 'table-cell' elements.

In this XML example, a 'table' element is assumed to contain the HBOX element:

<HBOX>
  <VBOX>George</VBOX>
  <VBOX>4287</VBOX>
  <VBOX>1998</VBOX>
</HBOX>

because the associated style sheet is:

HBOX {display: table-row}
VBOX {display: table-cell}

In this example, three 'table-cell' elements are assumed to contain the text in the ROWs. Note that the text is further encapsulated in anonymous inline boxes, as explained in visual rendering model:

<STACK>
  <ROW>This is the <D>top</D> row.</ROW>
  <ROW>This is the <D>middle</D> row.</ROW>
  <ROW>This is the <D>bottom</D> row.</ROW>
</STACK>

The style sheet is:

STACK {display: inline-table}
ROW {display: table-row}
D {display: inline; font-weight: bolder}

HTML user agents are not required to create anonymous boxes according to the above rules.

18.3 Column selectors

Table cells may belong to two contexts: rows and columns. However, in the source document cells are descendants of rows, never of columns. Nevertheless, some aspects of cells can be influenced by setting properties on columns.

The following properties apply to column and column-group elements:

'border'
The various border properties apply to columns only if 'border-collapse' is set to 'collapse' on the table element. In that case, borders set on columns and column groups are input to the conflict resolution algorithm that selects the border styles at every cell edge.
'background'
The background properties set the background for cells in the column, but only if both the cell and row have transparent backgrounds. See "Table layers and transparency."
'width'
The 'width' property of the column only applies if the fixed layout algorithm is selected on the 'table-layout' property.
'column-span'
The number of grid columns spanned by this column or column group.
'visibility'
If the 'visibility' of a column is set to 'collapse', none of the cells in the column are rendered, and cells that span into other columns are clipped. In addition, the width of the table is diminished by the width the column would have taken up. See "Dynamic effects" below. Other values for 'visibility' have no effect.

Here are some examples of style rules that set properties on columns. The first two rules together implement the "rules" attribute of HTML 4.0 with a value of "cols". The third rule makes the "totals" column blue, the final two rules shows how to make a column a fixed size, by using the fixed layout algorithm.

COL {border-style: none solid}
TABLE {border-style: hidden}
COL.totals {background: blue}
TABLE {table-layout: fixed}
COL.totals {width: 5em}

18.4 Tables in the visual rendering model

In terms of the visual rendering model, a table may behave like a block-level or replaced inline-level element.

In both cases, the table element generates an anonymous box that contains the table box itself and the caption's box (if present). The table and caption boxes retain their own content, padding, margin, and border areas, and the dimensions of the rectangular anonymous box are the smallest required to contain both. Vertical margins collapse where the table box and caption box touch. Any repositioning of the table must move the entire anonymous box, not just the table box, so that the caption follows the table.

A table with a caption above
it; both have margins and the margins between them are collapsed, as
is normal for vertical margins.

Diagram of a table with a caption above it; the bottom margin of the caption is collapsed with the top margin of the table.

18.4.1 Caption position and alignment

'caption-side'
Value:  top | bottom | left | right | inherit
Initial:  top
Applies to:  'table-caption' elements
Inherited:  yes
Percentages:  N/A
Media:  visual

This property specifies the position of the caption box with respect to the table box. Values have the following meanings:

top
Positions the caption box above the table box.
bottom
Positions the caption box below the table box.
left
Positions the caption box to the left of the table box.
right
Positions the caption box to the right of the table box.

Captions above or below a 'table' element are rendered very much as if they were a block element before or after the table, except that (1) they inherit inheritable properties from the table, and (2) are not considered to be a block box for the purposes of any 'compact' or 'run-in' element that may precede the table.

The width of a caption that is above or below a 'table' element is computed as if the caption were a block-level child of the table's parent. In other words, the width of the caption is independent of the width of the table.

The width of a caption that is on the left or right side of the table must be set explicitly. The default value ('auto') will result in the narrowest possible box.

To align caption content horizontally within the caption box, use the 'text-align' property. For vertical alignment of captions on the left or right side, use the 'vertical-align' property. The only meaningful values in this case are 'top', 'middle', and 'bottom'. All other values are treated the same as 'top'.

In this example, the 'caption-side' property places captions below tables. The caption will be as wide as the parent of the table, and caption text will be left-justified.

CAPTION { caption-side: bottom; 
          width: auto;    /* default */
          text-align: left }

The following example shows how to put a caption in the left margin. The table itself is centered, by setting its left and right margins to 'auto', and the whole box with table and caption is shifted into the left margin by the same amount as the width of the caption.

BODY {
    margin-left: 8em
}
TABLE {
    margin-left: auto;
    margin-right: auto
}
CAPTION {
    caption-side: left;
    margin-left: -8em;
    width: 8em;
    text-align: right;
    vertical-align: bottom
}

Assuming the width of the table is less than the available width, the rendering will be similar to this:

A centered table with a
caption in the left margin of the page

Diagram showing a centered table with the caption extending into the left margin, as a result of a negative 'margin-left' property.

18.5 Visual layout of table contents

Like other elements of the document language, table elements generate rectangular boxes with content, padding, border, and margin areas.

18.5.1 Row and column spans: 'column-span', and 'row-span'

'row-span'
Value:  <integer> | inherit
Initial:  1
Applies to:  'table-cell' elements
Inherited:  no
Percentages:  N/A
Media:  visual

This property specifies the <integer> number of rows spanned by a cell.

'column-span'
Value:  <integer> | inherit
Initial:  1
Applies to:  'table-cell', 'table-column', and 'table-column-group' elements
Inherited:  no
Percentages:  N/A
Media:  visual

This property specifies the <integer> number of grid columns spanned by a cell, column, or column group.

The visual layout of these boxes is governed by a rectangular, irregular grid of rows and columns. Each box occupies a whole number of grid cells, determined according to the following rules. These rules do not apply to HTML 4.0 or earlier HTML versions; HTML imposes its own limitations on row and column spans.

  1. Each row box occupies one row of grid cells. Together, the row boxes fill the table from top to bottom in the order they occur in the source document (i.e., the table occupies exactly as many grid rows as there are row elements).
  2. A row group occupies the same grid cells as the rows it contains.
  3. Columns are placed next to each other in the order they occur. Each one occupies the number of grid columns given by its 'column-span' property. The first column may be either on the left or on the right, depending on the value of the 'direction' property of the table.
  4. A column group occupies the same grid cells as the columns it contains.

    [Not true, need correct description.]

  5. Structurally speaking, each cell belongs to one row and column; this row and column determine the coordinates of the cell. Visually, each cell occupies a rectangle of 'column-span' grid cells wide and 'row-span' grid cells high. The top row of this rectangle of grid cells must be the row specified by the cell's parent. The rectangle must be as far to the left as possible, but it may not overlap with any other cell, and must be to the right of all cells in the same row that are earlier in the source document. (If the 'direction' of the table is 'right-to-left', interchange "left" and "right" in the previous sentence.)
  6. Cells are 'row-span' high only if there are enough rows: a cell cannot extend below the last row box; it is made shorter until it fits.

Here is an example:

<TABLE>
<TR><TD>1 <TD rowspan=2>2 <TD>3 <TD>4
<TR><TD colspan=2>5
</TABLE>

This table is in error. According to HTML 4.0, the rendering on the left is allowed. However, CSS2 UAs must render this table as in the figure on the right:

two renderings of an erroneous table

Two renderings of an erroneous HTML 4.0 table. The rendering on the left is allowed by HTML 4.0, but in CSS2 the one on the right is compulsory.

18.5.2 Table layers and transparency

For the purposes of finding the background of each table cell, the different table elements may be thought of as being on six superimposed layers. The background set on an element in one of the layers will only be visible if the layers above it have a transparent background.

schema of table layers

Schema of table layers.

  1. The lowest layer is a single plane, representing the table box itself. Like all boxes, it may be transparent.

  2. The next layer contains the column groups. The columns groups are as tall as the table, but they need not cover the whole table horizontally.

  3. On top of the column groups are the areas representing the column boxes. Like column groups, columns are as tall as the table, but need not cover the whole table horizontally.

  4. Next is the layer containing the row groups. Each row group is as wide as the table. Together, the row groups completely cover the table from top to bottom.

  5. The last but one layer contains the rows. The rows also cover the whole table.

  6. The topmost layer contains the cells themselves. As the figure shows, although all rows contain the same number of cells, not every cell may have specified content These "empty" cells are transparent, letting lower layers shine through.

In the following example, the first row contains four cells, but the second row contains no cells, and thus the table background shines through, except where a cell from the first row spans into this row. The following HTML code and style rules

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
  <HEAD>
    <STYLE type="text/css">
      TABLE { background: #ff0; border-collapse: collapse }
      TD { background: red; border: double black }
    </STYLE>
  </HEAD>
  <BODY>
    <P>
    <TABLE>
      <TR>
        <TD> 1 
        <TD rowspan="2"> 2
        <TD> 3 
        <TD> 4 
      </TR>
      <TR><TD></TD></TR>
    </TABLE> 
  </BODY>
</HTML>

might be rendered as follows:

Table with three empty cells
in bottom row

Table with three empty cells in the bottom row.

18.5.3 Table size algorithms: the 'table-layout' property

CSS does not define an "optimal" layout for tables since, in many cases, what is optimal is a matter of taste. CSS does define constraints that user agents must respect when laying out a table. User agents may use any algorithm they wish to do so, and are free to prefer rendering speed over precision, except when the "fixed layout algorithm" is selected.

'table-layout'
Value:  auto | fixed | inherit
Initial:  auto
Applies to:  'table' and 'inline-table' elements
Inherited:  no
Percentages:  N/A
Media:  visual

The 'table-layout' property controls the algorithm used to lay out the table cells, rows, and columns. Values have the following meaning:

fixed
Use the fixed table layout algorithm
auto
Use any automatic table layout algorithm

The two algorithms are described below.

Fixed table layout

With this (fast) algorithm, the horizontal layout of the table does not depend on the contents of the cells; it only depends on the table's width and the width of the columns.

The table's width is determined by the 'width' property. If the value is 'auto', the table is as wide as the available horizontal space.

The width of each column is determined as follows:

  1. A column element with a value other than 'auto' for the 'width' property sets the width for that columns.
  2. Otherwise, a cell in the first row with a value other than 'auto' for the 'width' property sets the width for that column. If the cell spans columns, the width is divided over the columns.
  3. Any remaining columns equally divide the remaining space.

In this manner, the user agent lays out the first row of the table immediately upon receiving the content. All subsequent rows have the same widths of columns of cells; nothing in subsequent rows can affect the widths of the columns. Any cell that has content that overflows its dimensions uses the 'overflow' property to determine how to handle the overflow content. However, a value of 'visible' will not increase the cell box dimensions; cell content will flow into the adjacent cell.

With this algorithm, the height of a row of cells may either be computed dynamically (the 'auto' value), or may be set explicitly, in which case overflow is handled in the same manner as with the width dimension.

It is possible that the sum of the widths of the columns exceeds the table's width. In that case the larger width is used as the actual value of the table's 'width' property.

Automatic table layout

This is a multiple-pass algorithm in which a table width is given by the width of its columns (and intervening borders). This algorithm reflects the behavior of several popular HTML user agents at the writing of this specification. UAs are not required to implement this algorithm to determine the table layout in the case that 'table-layout' is 'auto'; they can use any other algorithm.

In this algorithm, the width of each column is based on the largest unbreakable element in a cell in that column. This algorithm may be inefficient since it may demand multiple passes and requires the user agent to have access to all the content in the table before determining the final layout.

For this algorithm, a value of 'auto' for the 'width' property for the table element means that the final table width is computed dynamically: it is the sum of the column widths and the borders between them.

Column widths are determined as follows:

  1. For each cell determine the minimum and maximum widths needed. Cells with a given 'width' get a minimum width equal to the greater of the specified width and the minimum needed width.
  2. For each column determine a maximum and minimum width from the cells with a colspan of 1. If the column has a 'width' greater than the minimum over the cells, then the 'width' is used as the minimum width for the column.
  3. For each cell with a colspan of more than one, increase the minimum and maximum widths of the columns it spans enough so the combined minimum/maximum widths are at least those of the cell. If possible, widen all spanned columns by approximately the same amount.

Now we have a maximum and minimum width per column. We now determine final column widths. Cell spacing is appropriately added into these calculations.

If there is a table width given, and it is larger than the minimum width needed, use it, and distribute the width over the columns in some way.

Note that a table may thus be wider than its 'width' property.

If the table width is 'auto', there are three cases:

  1. If the maximum needed width for the table is less than the width of the table's containing block, use the maximum width.
  2. If the minimum width needed is greater than the width of the containing block, use the minimum width.
  3. Otherwise, use the width of the containing block and distribute the width over the columns in some way.

A percentage is relative to the table width. If the table's width is 'auto', a percentage represents a constraint on the column's width, which a UA should try to satisfy. (Obviously, this is not always possible: if the column's width is '110%', the constraint cannot be satisfied.)

Note. In this algorithm, rows (and row groups) and columns (and column groups) both constrain and are constrained by the dimensions of the cells they contain. Setting the width of a column may indirectly influence the height of a row, and vice versa.

18.5.4 Alignment of cell boxes

Cells may be aligned vertically (within a row) and horizontally (within a column).

Note. Table cells may be relatively and absolutely positioned, but this is not recommended: positioning and floating remove a box from the flow, affecting table alignment.

Vertical alignment in a row

The height of a cell's box is constrained by the rows that contain it. A cell may be smaller than a row, in which case its vertical alignment is governed by the 'vertical-align' property (much as an inline box is aligned within a line box).

Each cell's content has a baseline, a top, a middle, and a bottom, and so does the row itself. The value of the 'vertical-align' property of the cells determines on which of these lines they are aligned. In the context of tables, values have the following meanings:

baseline
The baseline of the cell is put at the same height as the baseline of the row (see below for the definition of baselines of cells and rows)
top
The top of the cell box is aligned with the top of the row
bottom
The bottom of the cell box is aligned with the bottom of the row
middle
The center of the cell is aligned with the center of the row
sub, super, text-top, text-bottom
These values do not apply to cells; the cell is aligned at the baseline instead

The baseline of a cell is the baseline of the first line of text in the cell. If there is no text, the baseline is the baseline of whatever object is displayed in the cell, or, if it has none, the bottom of the cell box. The maximum distance between the top of the cell box and the baseline over all cells that have 'vertical-align:baseline' is used to set the baseline of the row. Here is an example:

Example of vertically
aligning the cells

Diagram showing the effect of various values of 'vertical-align' on table cells.

Cell boxes 1 and 2 are aligned at their baselines. Cell box 2 has the largest height above the baseline, so that determines the baseline of the row. Note that if there is no cell box aligned at its baseline, the row will not have (nor need) a baseline.

To avoid ambiguous situations, the alignment of cells proceeds in a certain order. First the cells that are aligned on their baseline are positioned. This will establish the baseline of the row. Next the cells with alignment 'top' are positioned.

The row now has a top, possibly a baseline, and a provisional height, which is the distance from the top to the lowest bottom of the cells positioned so far. (See conditions on the cell padding below.)

If any of the remaining cells, those aligned at the bottom or the middle, have a height that is larger than the current height of the row, the height of the row will be increased to the maximum of those cells, by lowering the bottom.

Finally the remaining cells are positioned.

Cells that are smaller than the height of the row will get extra padding added at their top or bottom. As a result, the padding area at the top and bottom of each cell box after positioning must be at least as large as the 'padding' property specifies.

Horizontal alignment in a column

The horizontal alignment of a cell's contents within a cell box is specified with the 'text-align' property.

Cell boxes in the same column may also be aligned horizontally along a common axis, specified by the 'text-align' property. The <string> value of this property specifies how cell boxes in the same column will align horizontally.

When the 'text-align' property for more than one cell in a column is set to a <string> the content of those cells is placed in such a way that the beginnings of the first occurrence of the string in the respective cells are placed directly over each other.

If a cell has a string-values 'text-align', but the string doesn't occur in the cell, the cell is aligned at the end of its content.

Note that the strings do not have to be the same for each cell, although they usually are.

Aligning text in this way is only useful if the text fits on one line. The result is undefined if the text spans more than one line.

The following style sheet:

   TD { text-align: "." }
   TD:before { text-align: right; content: "$" }

will cause the column of dollar figures in the following HTML table:

  <TABLE>
  <COL width="40">
  <TR> <TH>Long distance calls
  <TR> <TD> 1.30
  <TR> <TD> 2.50
  <TR> <TD> 10.80
  <TR> <TD> 111.01
  <TR> <TD> 85.
  <TR> <TD> 90
  <TR> <TD> .05
  <TR> <TD> .06
  </TABLE>

to align along the decimal point. For fun, we have used the :before pseudo-element to insert a dollar sign before each figure:

Long distance calls
              $1.30      
              $2.50
             $10.80
            $111.01
             $85.
             $90
               $.05
               $.06

18.5.5 Dynamic row and column effects

The 'visibility' property takes the value 'collapse' for row, row group, column, and column group elements. This value causes the entire row or column to be removed from the display, and the space normally taken up by the row or column to be made available for other content. The suppression of the row or column, however, does not otherwise affect the layout of the table. This allows dynamic effects to remove table rows or columns without forcing a re-layout of the table in order to account for the potential change in column constraints.

18.6 Borders

There are two distinct models for setting borders on table cells in CSS. One is most suitable for so-called "2D" borders around individual cells, the other is suitable for borders that are continuous from one end of the table to the other. Many border styles can be achieved with either model, so it is often a matter of taste which one is used.

'border-collapse'
Value:  collapse | separate | inherit
Initial:  collapse
Applies to:  'table' and 'inline-table' elements
Inherited:  yes
Percentages:  N/A
Media:  visual

This property selects a table's border model. The value 'separate' selects the separated borders border model. The value 'collapse' selects the collapsing borders model. The models are described below.

18.6.1 The separated borders model

'border-spacing'
Value:  <length> <length>? | inherit
Initial:  0
Applies to:  'table' and 'inline-table' elements
Inherited:  yes
Percentages:  N/A
Media:  visual
<length> <length>?
Use the separated borders model. In this case, the lengths specify the distance that separate adjacent cell borders. If one length is specified, it gives both the horizontal and vertical spacing. If two are specified, the first gives the horizontal spacing and the second the vertical spacing. Lengths may not be negative.

In this model, each cell has an individual border. The 'border-spacing' property specifies the distance between the borders of adjacent cells. This space is filled with the background of the table element. Rows, columns, row groups, and column groups cannot have borders (i.e., user agents must ignore the border properties for those elements.

The table in the figure below could be the result of a style sheet like this:

  TABLE      { border: outset 10pt; 
               border-collapse: separate;
               border-spacing: 15pt }
  TD         { border: inset 5pt }
  TD.special { border: inset 10pt }  /* The top-left cell */

A table with
border-spacing

A table with 'border-spacing' set to a length value. Note that each cell has its own border, and the table has a separate border as well.

When this border model is used, the overall width of the table is the sum of the cells plus the border spacing between all borders. See the section on automatic table layout for more information about table dimension calculations.

Borders around empty cells: the 'empty-cells' property

'empty-cells'
Value:  borders | no-borders | inherit
Initial:  borders
Applies to:  'table-cell' elements
Inherited:  yes
Percentages:  N/A
Media:  visual

In the separated borders model, this property controls the rendering of borders around cells that have no visible content. Empty cells and cells with the 'visibility' property set to 'hidden' are considered to have no visible content. Visible content includes "&nbsp;" and other whitespace except ASCII CR ("\0D"), LF ("\0A"), tab ("\09"), and space ("\20").

When this property has the value 'borders', borders are drawn around empty cells (like normal cells).

A value of 'no-borders' means that no borders are drawn around empty cells. Furthermore, if all the cells in a row have a value of 'no-borders' and have no visible content, the entire row behaves as if it had 'display : none'.

The following rule causes borders to be drawn around all cells:

TABLE { empty-cells: borders }

18.6.2 The collapsing border model

In the collapsing border model, it is possible to specify borders that surround all or part of a cell, row, row group, column, and column group. Borders for HTML's "rule" attribute can be specified this way.

Borders are centered on the grid lines between the cells. User agents must find a consistent rule for rounding off in the case of an odd number of discrete units (screen pixels, printer dots).

The diagram below shows how the width of the table, the widths of the borders, the padding, and the cell width interact. Their relation is given by the following equation, which holds for every row of the table:

row-width = border-width0 + padding-left1 + width1 + padding-right1 + border-width1 + padding-left2 +...+ padding-rightn + border-widthn

Here n is the number of cells in the row, and border-widthi refers to the border between cells i and i + 1.

Schema showing the widths of
cells and borders and the padding of cells

Schema showing the widths of cells and borders and the padding of cells.

Note that in this model, the width of the table includes half the table border. Also, in this model, a table doesn't have padding (but does have margins).

Border conflict resolution

In the collapsing border model, borders at every edge of every cell may be specified by border properties on a variety of elements that meet at hat edge (cells, rows, row groups, columns, column groups, and the table itself), and these borders may vary in width, style, and color. The following rules determine which border style "wins" in case of a conflict:

The rule of thumb is that at each edge the most "eye catching" border style is chosen, except that any occurrence of the style 'hidden' unconditionally turns the border off.

  1. Borders with the 'border-style' of 'hidden' take precedence over all other conflicting borders. Any border with this value suppresses all borders at this location.
  2. Borders with a style of 'none' have the lowest priority. Only if the border properties of all the elements meeting at this edge are 'none' will the border be omitted (but note that 'none' is the default value for the border style.)
  3. If none of the styles is 'hidden' and at least one of them is not 'none', then narrow borders are discarded in favor of wider ones. If several have the same 'border-width' than styles are preferred in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'.
  4. If border styles differ only in color, then a style set on a cell wins over one on a row, which wins over a row group, column, column group and, lastly, table.

The following example illustrates the application of these precedence rules. This style sheet:

  TABLE          { border-collapse: collapse;
                   border: 5px solid yellow; }
  *#col1         { border: 1px solid black; }
  TD             { border: 5px solid red; }
  TD.solid-blue  { border: 11px solid blue; }
  TD.solid-green { border: 7px solid green; }

with this HTML source:

<P>
<TABLE>
<COL id="col1"><COL id="col2"><COL id="col3">
<TR id="row1">
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
</TR>
<TR id="row2">
    <TD>&nbsp;</TD>
    <TD class="solid-blue">&nbsp;</TD>
    <TD class="solid-green">&nbsp;</TD>
</TR>
<TR id="row3">
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
</TR>
<TR id="row4">
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
</TR>
<TR id="row5">
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
    <TD>&nbsp;</TD>
</TR>
</TABLE>

would produce something like this:

[IMAGE HERE]

An example of a table with collapsed borders.

The next example shows a table with horizontal rules between the rows. The top border of the table is set to 'hidden' to suppress the top border of the first row. This implements the RULES="rows" attribute of HTML 4.0.

TABLE[rules=rows] TR {border-top: solid}
TABLE[rules=rows] {border-collapse: collapse; 
                   border-top: hidden}

Table with horizontal
rules

Table with horizontal rules between the rows.

In this case the same effect can also be achieved without setting a 'hidden' border on TABLE, by addressing the first row separately. Which method is preferred is a matter of taste.

TR:first-child {border-top: none}
TR {border-top: solid}

Here is another example of hidden collapsing borders:

Table
with two omitted borders

Table with two omitted internal borders.

HTML source:

<TABLE style="border-collapse: collapse; border: solid;">
<TR><TD style="border-right: hidden; border-bottom: hidden">foo</TD>
    <TD style="border: solid">bar</TD></TR>
<TR><TD style="border: none">foo</TD>
    <TD style="border: solid">bar</TD></TR>
</TABLE>

18.6.3 Border styles

Some of the values of the 'border-style' have different meanings in tables than for other elements. In the list below they are marked with an asterisk.

none
No border.
*hidden
Same as 'none', but in the collapsing border model, also inhibits any other border (see the section on border conflicts).
dotted
The border is a series of dots.
dashed
The border is a series of short line segments.
solid
The border is a single line segment.
double
The border is two solid lines. The sum of the two lines and the space between them equals the value of 'border-width'.
groove
The border looks as though it were carved into the canvas.
ridge
The opposite of 'grove': the border looks as though it were coming out of the canvas.
*inset
In the 2D border model, the border makes the entire box look as though it were embedded in the canvas. In the collapsing border model, same as 'groove'.
*outset
In the 2D border model, the border makes the entire box look as though it were coming out of the canvas. In the collapsing border model, same as 'ridge'.

18.7 Audio rendering of tables

When a table is spoken by a speech generator, the relation between the data cells and the header cells must be expressed in a different way than by horizontal and vertical alignment. Some speech browsers may allow a user to move around in the 2-dimensional space, thus giving them the opportunity to map out the spatially represented relations. When that is not possible, the style sheet must specify at which points the headers are spoken.

18.7.1 Speaking headers: the 'speak-header' property

'speak-header'
Value:  once | always | inherit
Initial:  once
Applies to:  elements that have header information
Inherited:  yes
Percentages:  N/A
Media:  aural

This property specifies whether table headers are spoken before every cell, or only before a cell when that cell is associated with a different header than the previous cell. Values have the following meanings:

once
The header is spoken one time, before a series of cells.
always
The header is before every pertinent cell.

Each document language may have different mechanisms that allow authors to specify headers. For example, in HTML 4.0 ([HTML40]), it is possible to specify header information with three different attributes ("headers", "scope", and "axis"), and the specification gives an algorithm for determining header information when these attributes have not been specified.

Image of a table created in MS
Word

Image of a table with header cells ("San Jose" and "Seattle") that are not in the same column or row as the data they apply to.

This HTML example presents the money spent on meals, hotels and transport in two locations (San Jose and Seattle) for successive days. Conceptually, you can think of the table in terms of a n-dimensional space. The headers of this space are: location, day, category and subtotal. Some cells define marks along an axis while others give money spent at points within this space. The markup for this table is:

<TABLE>
<CAPTION>Travel Expense Report</CAPTION>
<TR>
  <TH></TH>
  <TH>Meals</TH>
  <TH>Hotels</TH>
  <TH>Transport</TH>
  <TH>subtotal</TH>
</TR>
<TR>
  <TH id="san-jose" axis="san-jose">San Jose</TH>
</TR>
<TR>
  <TH headers="san-jose">25-Aug-97</TH>
  <TD>37.74</TD>
  <TD>112.00</TD>
  <TD>45.00</TD>
  <TD></TD>
</TR>
<TR>
  <TH headers="san-jose">26-Aug-97</TH>
  <TD>27.28</TD>
  <TD>112.00</TD>
  <TD>45.00</TD>
  <TD></TD>
</TR>
<TR>
  <TH headers="san-jose">subtotal</TH>
  <TD>65.02</TD>
  <TD>224.00</TD>
  <TD>90.00</TD>
  <TD>379.02</TD>
</TR>
<TR>
  <TH id="seattle" axis="seattle">Seattle</TH>
</TR>
<TR>
  <TH headers="seattle">27-Aug-97</TH>
  <TD>96.25</TD>
  <TD>109.00</TD>
  <TD>36.00</TD>
  <TD></TD>
</TR>
<TR>
  <TH headers="seattle">28-Aug-97</TH>
  <TD>35.00</TD>
  <TD>109.00</TD>
  <TD>36.00</TD>
  <TD></TD>
</TR>
<TR>
  <TH headers="seattle">subtotal</TH>
  <TD>131.25</TD>
  <TD>218.00</TD>
  <TD>72.00</TD>
  <TD>421.25</TD>
</TR>
<TR>
  <TH>Totals</TH>
  <TD>196.27</TD>
  <TD>442.00</TD>
  <TD>162.00</TD>
  <TD>800.27</TD>
</TR>
</TABLE>

By providing the data model in this way, authors make it possible for speech enabled-browsers to explore the table in rich ways, e.g. each cell could be spoken as a list, repeating the applicable headers before each data cell:

  San Jose, 25-Aug-97, Meals:  37.74
  San Jose, 25-Aug-97, Hotels:  112.00
  San Jose, 25-Aug-97, Transport:  45.00
 ...

The browser could also speak the headers only when they change:

San Jose, 25-Aug-97, Meals: 37.74
    Hotels: 112.00
    Transport: 45.00
  26-Aug-97, Meals: 27.28
    Hotels: 112.00
...