A table, at least in HTML, is much more complex than a collection of cells organized in rows and columns. The cells can span columns and rows. They can be grouped by virtue of having the same class. The rows are grouped into row groups, the columns are grouped into column groups.
This is an attempt to define a consistent model for referring to the borders around each of these objects. It is also an attempt to define a general method for describing the form of as many different types of rules as possible.
Contents: Rule types | Rules or borders? | Spacing | User interface considerations | Syntax | Example syntax | Examples | Alternative syntax
A quick scan through magazines and books led to an initial list of rule styles:
|A single line, extending till the edge of the table. Parameters: width, color/pattern.|
|A single line, not extending till the edge of the table. Parameters: width, color/pattern, gap.|
|Double line, special treatment at corners. Parameters: 3 widths, 2 colors/patterns.|
|Dashed line, ideally it is nicely balanced at the corners. Parameters: width, dash length, gap length, color/pattern.|
|Dotted line, ideally with a dot in every corner. Parameters: width, gap length, color/pattern.|
|Beveled line, either inset or outset, special treatment in corners. Parameters: width. Note that color depends on environment.|
|Ridge, special treatment in corners. Parameters: 3 widths.|
|Short ridge, does not extend to the edge of the table. Parameters: 3 widths, gap.|
|Groove, special treatment in corners. Parameters: 3 widths.|
|Short groove, does not extend to the edge of the table. Parameters: 3 widths, gap.|
|Drop shadow. Parameters: 2 widths.|
It is possible to consider the rules as rules on the edge of something (cell, column, table, etc.), as rules between things, or as borders around things. Sometimes one model seems easier than another, but mixing models may not be the best solution.
In the HTML table model, there are 7 types of objects: table (table), row group (thead, tbody, tfoot), row (tr), column group (colgroup), column (col), cell (td, th), cell group (class attribute). Only 3 of them correspond to well defined areas of the table (i.e., areas that you can draw a border around): table, row group, cell.
The others may or may not correspond to a visible area. The column and the row may contain cells that span other columns and rows. The same is true of column groups. The cell group can be irregularly shaped, even disjoint.
However, these four irregular groups may sometimes need borders, if only in places where the group's border coincides with a cell's border. One way of achieving this is to set the border on the cell, but with a condition (selector) on the cell being part of a certain group. One could also specify that rules on their edges are only defined (and thus drawn) when the edge coincides with a cell's edge.
The cell group (on the basis of equal class values) is a strange kind of object. It has been proposed as a mechanism to group a sub-table of a larger table, but nowhere else in HTML are elements with equal classes treated as a single object.
The three `regular' table elements (table, row group, cell) can have borders. Since these elements also nest inside each other, they can even have each their own border (and a margin/padding in between). However, it is not very intuitive to view tables as a three level nesting. It seems much easier to view the edge of the table as being the same edge as the edge of the cell at that point.
Note: if a cell spans two rows and the rows have different border styles, what style is the cell drawn in? Do we want to require that an edge can only have one style, or is it possible that the lower half of the evrtical edge has a different style from the upper half of the same edge?
Between the rules and the text of the cells there is almost always a little space. That space is usually constant throughout the table, though there are exceptions.
One exception is that the space is normally different if there is a rule from when there is no rule. In other words, in a given table the text of two cells is further apart when there is a thin rule in between, than when there is no rule at all.
It is much harder to describe the rules then it is to draw them. In a WYSIWYG editor, the factor time is used to draw general rules and then override them locally. In a static language other means are needed.
One way is to rely on fixed rules, like: thicker rules win over thinner ones, or: last specified wins. Another way is to set explicit (numerical) priorities, or add a special border style called `as-is' or `inherit'. Maybe a combination of these methods is needed.
Often, the result of adding rules is that there are a few heavy rules and light rules everywhere else. In many cases one could describe this as an external border around something and internal borders inside the same thing. But in the WYSISWYG mode one can also look at it as applying light borders everywhere and then replacing them locally.
This works if the replaced borders correspond to an element, since you can select that element and apply a border to it. However, in the case of the grouping by class attributes, there is no single element to select and put a border on.
This rather seems like an argument against viewing the cell group as a real object, with a single boundary.
The most common case seems to be that the rules on the edges of `larger' groupings are not interrupted. (`Larger' in the sense of being ancestor in the nesting.) In other words: edges of the table or the row groups stretch uninterrupted from one table edge to another. The main exception is the case where the table itself has no visible border: that invisible border can be replaced by a visible border around a cell or a group.
Another way of looking at this is to note that it is usually the `heavier' borders that are uninterrupted. `Heavier' relates to the thickness of the rule or the style or maybe a combination of both: thick single lines seem to override thin single lines, double lines seem to override single lines, etc.
However, it's my impression that the rule about `heavier' edges is more often broken than the one about `larger' objects.
Since the parameters of the various rule styles depend on the style, it makes
sense to put them in the style in some way, instead of in separate
properties. For example, the styles could be seen as function with arguments:
In CSS1, to address the edges, one must set properties on elements. Since an edge is sometimes shared by a number of elements, there are many ways to address the same edge, which means that conflict resolution is needed for this problem as well.
If two or more rule styles conflict, they can conflict in the style itself, or in the parameters.
The observation that `larger' objects usually have uninterrupted borders, leads to a basic disambiguating rule that the border of a table is always drawn, the border of a row group only where it doesn't coincide with the table's border, and the cell borders are only drawn when they don't coincide with any row group's. The exception is the `no border' style, which is always overridden by any visible border.
Extending the rule to columns, column groups and rows could be as simple as stating that their borders are only drawn if they fall on edges with a `no border' style. (They probably need some precedence among themselves, though.)
The observation that heavier rules are usually uninterrupted would lead to a precedence based on border width and style.
Maybe the two methods can be combined: in case of a conflict between elements of the same type, the widest border wins. If the borders are the same width, `heavier' styles win.
Here is an example of a possible syntax. It assumes that `larger' objects take precedence over `smaller' ones, as stated above.
value: <style> || <color> || <uri> ||
[<length> | medium | thick | thin]
Values on `border' apply to all four borders. See CSS1.
Values for <style> are: none, blank, solid, double(p,q,r), dashed(s,t), dotted(t), ridge(p, q,r), groove(p,q,r). p, q and r are numbers representing the relative widths of the outer line/shadow, the middle area and the inner line/shadow. Only their relative values counts, the numbers themselves have no meaning. s is the length of the dashes, in any of the normal units, t is the length of the gap between the dashes or dots.
The difference between styles `none' and `blank' is that `none' can be overridden by `smaller' elements, while `blank' can't. Otherwise they look the same. They have no width, even if one is specified explicitly.
The `dotted' style might need two instead of one parameter, if the diameter of the dots has to be independent from the border width.
The <style> may be accompanied by the keyword `override', in which case this style overrides a style set on a `larger' element (unless that also has the keyword `override').
The parameters can be omitted, in which case application dependent defaults are used.
If omitted, the color is the element's (foreground) color, the border width is `medium', the style is `solid'.
Note that short rules and drop shadows are not yet supported (can't find a name for the opposite of a drop shadow: if one cell has a drop shadow what is it that the next cell has?). But see example 11 below.
The margin properties work normally for the table element, but they don't apply to row groups, rows, column groups, columns, and cells.
Padding applies normally to cells, but doesn't apply to any other table element.
Width and height can probably be applied to all table elements, but there will be complicated interactions. One guiding principle can be that widths are computed inside out: the widest cell determines the minimum width of the column, the sum of the columns determines the minimum width of the table.
Note that border widths have to be added as well. See below.
When borders of different width are used in one column or row, they should not disrupt the visual alignment of the cells. The best solution seems to be to align all borders on their centers. Compare the two figures below:
This has implications for the computation of the column widths and therefore the table width.
A few examples: