Styling HTML3 Tables

Dave Raggett, 17th April 1996

This is a proposal for extending CSS to support HTML tables as defined RFC XXXX. HTML tables allow you to group rows and columns, and to create cells that span multiple rows or columns. You can set which sides of the table frame are rendered, and which rules to draw between rows and columns.

The above drawing illustrates some of the aspects that can be controlled. The Netscape Navigator browser has popularised tables with 3D borders. The table frame is outset from the plane of the document while table cells are inset. You can set the spacing between cells with CELLSPACING and the padding of cell contents with CELLPADDING.

The richer table model developed in 1995 allows you to include lines drawn between rows and columns in addition to the lines around cells themselves. An obvious rendering of these rules is as grooves in between the cells, for instance:

This splits the CELLSPACING parameter into two new parameters: CELLMARGIN and TABLEPADDING, making it possible to set different values for the spacing between cells, and the spacing between the cells and the table frame. In the case where these are the same, the following equality holds:

  CELLSPACING = 2 * CELLMARGIN = CELLMARGIN + TABLEPADDING

CSS provides the generic properties MARGIN and PADDING. These can be set as properties for given HTML tags, e.g.

    table {padding: 8px}
    th {margin: 6px}
    td {margin: 6px}

This example sets the padding for the TABLE element to 8 pixels and the margin for table cells to 6 pixels. HTML tables use the TH element for header cells and TD for data cells. As the example suggests, it will be possible to set different margin values for different cells. CSS also allows you to associate properties with particular cells according to their attributes. The consequence is that different cells on the same row may end up with different heights when the margins are included.

To deal with this, the margin above and below each cell should be set to the largest margin for any of the cells in each row. Similarly, the margin to the left and right of each cell should be set to the largest margin for any of the cells in each column. Cells spanning more than one row or column complicate these rules. For each row or column, you ignore cells which don't start or end in this row or column. The complexity of this search process can be simply avoided if CSS is restricted to a CELLMARGIN parameter associated with the TABLE element.

Note that exactly the same problem arises when the cells have differing border widths.

The illustration shows two cells with differing margins and border widths. The margin for the cell on the right is increased beyond the value specified with the margin property to fill the same height as the cell on the left. The right cell is slightly narrower that other cells on the same column, so its left and right margin are likewise expanded to fill the column width. The adjustments to the cell margins are made so that the inside edge of the borders fall on the same horizontal and vertical lines. Note that these adjustments also deal with varying border widths.

Properties associated with the TABLE element

Many of the properties allow you to give from one to four values. The order is top, right, bottom, left. If there is only one value, it applies to all sides, if there are two or three, the missing values are taken from the opposite side.

What does it mean if there are only two or three values? The above isn't sufficiently clear. <left> [<top> [<right> [<bottom>]]] would make more sense to me.

Border-Style

This sets the style of the border. You can supply one to four values to set the border style independently for each of the four sides. The possible values are:

INSET
A 3D inset, with a light color to the right and bottom; and a dark color to the left and top.
OUTSET
A 3D outset, with a dark color to the right and bottom; and a light color to the left and top.
GROOVE
A 3D groove, with the left and right sides drawn with a light colored line to the immediate left of a dark colored line. The top and bottom sides are drawn with a dark colored line immediately above a light colored line.
RIDGE
A 3D ridge, with the left and right sides drawn with a dark colored line to the immediate left of a light colored line. The top and bottom sides are drawn with a light colored line immediately above a dark colored line.
DOTTED
A simple dotted line.
DASHED
A simple dashed (i.e. broken) line.
SOLID
A continous line.
DOUBLE
A double line made up from an outer thicker solid line next to a thinner inner solid line.

Border-Width

This property sets the width of the border. You can give from one to four values to set the widths of each of the four sides independently. The value is given in the standard CSS notation for lengths, e.g. border-width: 4px for a four pixel wide line. You can also use a keyword for the width, e.g. thin, medium and thick.

Certain border styles have a minimum width, e.g. groove must be 2 pixels wide or more, while double must be 3 pixels wide or more. If the border-width property is set to less than the minimum value for the specified border-style, then then the minimum value is used instead.

Border-Color

This sets the color for the border. You can give from one to four values to set the colors of each of the four sides independently. Color values are given using the standard CSS notation for colors, e.g. border-color: #0000C0 for a dark blue border.

What about a syntax like "border-color: rgb(0, 0, 192)" allowing you to specify colors as decimal values which are much easier for users to get hold of than the hexadecimal equivalents.

For border styles involving a 3D effect, how can you give a pair of color values corresponding to the light and dark colors needed for these effects? I would suggest a paired notation, e.g. "light/dark" where the words light and dark are replaced by the corresponding color values.

Border

This allows you to give values for width, style and color in one go: e.g. "border: thin solid black". It is formally defined as:

border: <border-width> [<border-style> [< border-color>]]

Padding

This is used to set the table padding. One to four length values can be given using the standard CSS notation to set the padding for each of the four sides independently, e.g. padding: 4px.

CellMargin

This sets the value for cell margins. Like padding, you can supply one to four length values, e.g. cellmargin: 4px. This property is only needed if we want to avoid the search process for dealing different cell margins for cells in a given row or column.

CellPadding

This is used to set the default cell padding for the table. One to four length values can be given using the standard CSS notation to set the padding for each of the four sides independently, e.g. padding: 4px.


Rules between Rows and Columns

Like the HTML table model, the presence or absence of these rules is specified using the RULES property, which can be one of None, Groups, Rows, Cols or All, where:

NONE
Suppresses internal rulings.
GROUPS
The THEAD, TFOOT and TBODY elements divide the table into groups of rows, while COLGROUP elements divide the table into groups of columns. This choice places a horizontal rule between each row group and a vertical rule between each column group. Note that every table has at least one row and one column group.
ROWS
As RULES: GROUPS plus horizontal rules between all rows. User agents may choose to use a heavier rule between groups of rows and columns for emphasis.
COLS
As RULES: GROUPS plus vertical rules between all columns. User agents may choose to use a heavier rule between groups of rows and columns for added emphasis.
ALL
Place rules between all rows and all columns. User agents may choose to use a heavier rule between groups of rows and columns for added emphasis.

Rule-Style

This sets the style used for drawing rules. It can be one or two values from the following list. If two values are given, the first is used for vertical rules and the second for horizontal rules.

GROOVE
A 3D groove, with the left and right sides drawn with a light colored line to the immediate left of a dark colored line. The top and bottom sides are drawn with a dark colored line immediately above a light colored line.
RIDGE
A 3D ridge, with the left and right sides drawn with a dark colored line to the immediate left of a light colored line. The top and bottom sides are drawn with a light colored line immediately above a dark colored line.
DOTTED
A simple dotted line.
DASHED
A simple dashed (i.e. broken) line.
SOLID
A continous line.
DOUBLE
A double line made up from an outer thicker solid line next to a thinner inner solid line.

Rule-Width

This sets the width of the rule. One or two values are expected using the standard CSS notation for lengths. If two values are given, the first applies to vertical rules, while the second applies to horizontal rules.

Rule-Color

This sets the color of the rule. One or two values are expected using the standard CSS notation for colors. If two values are given, the first applies to vertical rules, while the second applies to horizontal rules.

This raises the same questions as for Border-Color.

Defining Rules with the TABLE element

The various rule properties can be used with the TABLE element, e.g.

    table {border-style: outset; border-width: 5px; rules: cols}

In this case the rules apply to both horizontal and vertical rules. between all rows and columns, including between row groups and column groups.

Defining Rules with the COLGROUP element

The rule-style, rule-width and rule-color properties can also be used with the COLGROUP element to set the properties of rules drawn between columns. This allows you to override the defaults set with the TABLE element. For example you can set a thicker rule between column groups as in:

    table {rules: cols; rule-style: solid; rule-width: 2px}
    colgroup {rule-width: 1px}

This draws rules between column groups 2 pixels wide, while rules between ordinary columns are drawn 1 pixel wide.

Define Rules with THEAD, TBODY and TFOOT

The rule-style, rule-width and rule-color properties can also be used with these element to set the properties of rules drawn between rows. This allows you to override the defaults set with the TABLE element. For example you can set a default for the table and override it for the table head:

    table {rules: rows; rule-style: dotted; rule-width: 1px}
    thead {rule-width: 0px}

This draws 1 pixel high lines between all rows except within the table head, where the rules are suppressed by setting their height to zero.

The rules property can also be used to give values for rule-width, rule-style and rule-color. Its formal definition is:

rules: none | groups | rows | cols | all
	[<rule-width> [&rule-style> [< rule-color>]]]

e.g. "rules: rows thin dotted black".

NoteShould we allow row-rule and col-rule properties to make it easy to specify different styles for rules between rows and columns?


Cell Properties

These properties apply to cell elements (TH and TD).

Border-Style

Defined exactly as for the same property for the TABLE element.

Border-Width

Defined exactly as for the same property for the TABLE element.

Border-Color

Defined exactly as for the same property for the TABLE element.

Border

Defined exactly as for the same property for the TABLE element.

Margin

This sets the margins for cells, and accepts one to four length value allowing you to set the margins for each of the four sides independently. In place of a length value, you can substitute the keyword "none". This causes adjacent cell borders to coincide.

Note that using the margin property for cells necessitates a search process for the largest margin in each row or column. See CELLMARGIN for a cheaper alternative, which can be used to set a default for the table.

Padding

This sets the internal padding for cells, and accepts one to four length value allowing you to set the padding for each of the four sides independently. CELLPADDING can be used to set the default for the table.

Problems with Border Widths

If cells on the same row or column use differing border widths, the user agent gets into the same difficulties as with differing cell margins, necessitating a search for the largest cell in the row or column. Note that this cannot be done in advance of parsing the table content as authors may have set border widths or cell margins with the style attribute on individual cells in the HTML markup. The style for each cell may also be dependent on the cell's class or id attributes. Implementors may wish to take a gambol on this for tables the author indicates can be rendered incrementally, and be prepared to repaint the table if this turns out to be needed when all of the table's data has been parsed.


Dealing with overlapping borders

When the cell margin property is set to "none", adjacent cell borders overlap. The user agent first should check the border widths for each of the borders involved. The one with the larger width takes precedence over the smaller one. If both borders have the same width, then a precedence order based on the border style properties is used to resolve the conflict.

One possible scheme is:

        double > solid > dashed > dotted

However, it is less clear what to do with styles involving 3D effects. Perhaps this should be left as implementation dependent?

If a cell border coincides with a table rule, then the rule takes precedence unless the rule is absent (e.g. if it is set to "none"). If the table padding is zero and the cell margin is "none", then the borders for outer cells will coincide with the table frame. In this situation the table frame takes precedence unless, it is absent (e.g. if it is set to "none").


Examples

Example 1

For a challenging table style, look at the "Nutrition Facts" table included with every cereal packet in the USA. I haven't had time to draw or scan one of these fully yet so reach for the cereals ...

On familia® muesli boxes, the legend "Cereal with 1/2 cup Vitamin A and D Fortified Skim Milk" is typeset with the text running vertical up the table. Most cereal packets give this horizontally though. This raises the issue of being able to alter the text direction in the style sheet, e.g. "run: up", "down" or "right".

The other notable feature is how "Dietary Fiber" and "Sugars" are indented along with the horizontal rule above these two rows. This could perhaps be achieved by "TR {padding-left: 3em}". One would then have to draw the border above "Dietary Fiber" and above "Sugars" on these cells, while setting the bottom border for "Total Carbohydrate" to none. Its not obvious how to do this with the rules properties because of the asymetry between "Total Carbohydrate" / "Dietary Fiber" and "Protein" / "Sugars". This may motivate using border properties on TR elements, though.


Example 2

<STYLE>
  table {border: thick outset; padding 3px}
  td {border: thin inset; margin: 3px}
</STYLE>

<TABLE>
<TR><TD>foo<TD>bar
<TR><TD>foo<TD>bar
</TABLE>

Example 3

<STYLE>
  table {border: thick outset; padding: 1px;
         rules: rows; rule-style: groove}
</STYLE>

<TABLE>
<TR><TD>foo<TD>bar
<TR><TD>foo<TD>bar
</TABLE>

Example 4

<STYLE>
  table {border: thick solid; padding none;
         rules: all thin solid}
</STYLE>

<TABLE>
<TR><TD>foo<TD>bar
<TR><TD>foo<TD>bar
</TABLE>

or perhaps as:

<STYLE>
  table {border: thick solid; padding: none}
  td {border: thin solid; margin: none}
</STYLE>

More Complex Rendering Models

Scrollable Regions

The HTML table model allows you to group rows and columns. For large tables, you might want to make regions of the table into scrolling regions with their own scroll bars. The model is designed to make it easy to keep the table head and foot fixed while scrolling the body rows. This could be controlled by a scroll property that indicates intended viewing area for the scrollable region. This property could be used for the TBODY element, but may also be worth supporting for individual cells, rows or columns. For TBODY, the viewable area could be specified as a single length value denoting the height of the viewable area. The width is given by the table width. For cells, one might want to give both a width and a height as an indication of the minimum size for each dimension when assigning row heights and column widths.

Borders around groups of cells

One possibility is for the author to drag select a group of cells and to set internal and external border properties for the group. This could be handled by setting the properties directly on each of the cells. Indeed, this is how most current word processing software works today. Another approach is to ask the author to create a class name for the group which is used to set the class attribute value for each of the cells. This is analogous to creating a new paragraph style for Word.

One can then associate different border properties for the internal and external border of the group. For instance "border-inner-style: dotted" and "border-style: solid". This would produce a solid line for the cell borders on the outside of the group and dotted lines for borders within the group. This works even for non-contiguous groups of cells. For isolated cells only the external border style matters. The internal style is only used when two cells in the group share a common border. This approach makes the most sense when the cell margins are set to "none" so that adjacent borders are coincident.

Borders around Rows, Columns, Row or Column Groups

It would be easy enough to extend CSS to allow the border, margin and padding properties to be used with the TR, THEAD, TBODY, TFOOT, COL and COLGROUP elements. This introduces the same problem as differing cell margins. For instance, you could define a thick border around a particular column. The other columns would then need to be adjusted to ensure that the cells in each row stay in alignment.

Column borders would fit between the inter-column rule and the cell borders. Column group borders would likewise fit between inter-column rule and the coloumn border. A similar situation applies to borders around rows and row groups. Precedence rules similar to those for cells would be needed to deal with overlapping borders when this arises.

Support for these additional borders seems like a relatively straightforward extension, once practical experience has been gained with the simpler model outlined in the current proposal.


References

Cascading Style Sheets
See http://www.w3.org/pub/WWW/TR/WD-css1.html.
WD-tables aka RFC XXXX
See http://www.w3.org/pub/WWW/TR/WD-tables.html.