DekGenius.com
Previous Section  < Day Day Up >  Next Section

11.1 Table Formatting

Before you can start to worry about how cell borders are drawn and tables sized, you need to delve into the fundamental ways in which tables are assembled, and the ways that elements within the table are related to each other. This is what is referred to as table formatting, and it is quite distinct from table layout: the latter is possible only after the former has been completed.

11.1.1 Visually Arranging a Table

The first thing to understand is how CSS defines the arranging of tables. While this knowledge may seem a bit basic, it's key to understanding how best to style tables.

CSS draws a distinction between table elements and internal table elements. In CSS, internal table elements generate rectangular boxes that have content, padding, and borders, but do not have margins. Therefore, it is not possible to define the separation between cells by giving them margins. A CSS-conformant browser will ignore any attempts to apply margins to cells, rows, or any other internal table element (with the exception of captions, which are discussed later in the chapter).

There are six rules for arranging tables. The basis of these rules is a "grid cell," which is one area between the grid lines on which a table is drawn. Consider Figure 11-1, in which two tables are shown along with their grid cells, which are indicated by the dashed lines drawn over the tables.

Figure 11-1. Grid cells form the basis of table layout
figs/css2_1101.gif

In a simple two-by-two table, such as the left-hand table shown in Figure 11-1, the grid cells correspond to the cells. In a more complicated table, like the right-hand one in Figure 11-1, the edges of the grid cells correspond to the cell borders of all the cells in the table, and cut through those cells that span rows or columns.

These grid cells are largely theoretical constructs, and they cannot be styled or even accessed through the document object model. They simply serve as a way to describe how tables are assembled for styling.

11.1.1.1 Table arrangement rules
  • 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 (with the exception of any table header or table footer row boxes, which come at the beginning and end of the table, respectively). 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 it contains.

  • A column box encompasses one or more columns of grid cells. All the 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 this 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 follow 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 would cause this condition, the cell must be shortened until it fits within the table or row group that encloses it.

The CSS specification discourages, but does not prohibit, the positioning of table cells and other internal table elements. Positioning a row that contains row-spanning cells, for example, could dramatically alter the layout of the table by removing the row from the table entirely, and thus removing the spanned cells from consideration in the layout of other rows.


By definition, grid cells are rectangular, but they do not all have to be the same size. All the grid cells in a given grid column will be the same width, and all the grid cells in a grid row will be the same height, but the height of one grid row may be different than that of another grid row. Similarly, grid columns may be of different widths.

With those basic rules in mind, a question may arise: how, exactly, do you know which elements are cells and which are not? We'll find out in the next section.

11.1.2 Table Display Values

In HTML, it's easy to know which elements are parts of tables because the handling of elements like tr and td is built into browsers. In XML, on the other hand, there is no way to intrinsically know which elements might be part of a table. This is where a whole collection of values for display come into play.

display


Values

none | inline | block | inline-block | list-item | run-in | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | inherit


Initial value

inline


Applies to

all elements


Inherited

no


Computed value

varies for floated, positioned, and root elements (see CSS2.1, section 9.7); otherwise, as specified


Note

the values compact and marker appeared in CSS2 but were dropped from CSS2.1 due to a lack of widespread support


In this chapter, we'll stick to the table-related values, as the others (block, inline, inline-block, run-in, and list-item) are discussed in other chapters. The table-related values can be summarized as follows:


table

This value specifies that an element defines a block-level table. Thus, it defines a rectangular block that generates a block box. The corresponding HTML element is, not surprisingly, table.


inline-table

This value specifies that an element defines an inline-level table. This means the element defines a rectangular block that generates an inline box. The closest non-table analogue is the value inline-block. The closest HTML element is table, although, by default, HTML tables are not inline.


table-row

This value specifies that an element is a row of cells. The corresponding HTML element is the tr element.


table-row-group

This value specifies that an element groups one or more rows. The corresponding HTML value is tbody.


table-header-group

This value is very much like table-row-group, except that for visual formatting, the header row group is always displayed before all other rows and row groups and after any top captions. In print, if a table requires multiple pages to print, a user agent may repeat header rows at the top of each page. The specification does not define what happens if you assign table-header-group to multiple elements. A header group can contain multiple rows. The HTML equivalent is thead.


table-footer-group

This value is very much like table-header-group, except that the footer row group is always displayed after all other rows and row groups and before any bottom captions. In print, if a table requires multiple pages to print, a user agent may repeat footer rows at the bottom of each page. The specification does not define what happens if you assign table-footer-group to multiple elements. This is equivalent to the HTML element tfoot.


table-column

This value declares that an element describes a column of cells. In CSS terms, elements with this display value are not visually rendered, as if they had the value none. Their existence is largely for the purposes of helping to define the presentation of cells within the column. The HTML equivalent is the col element.


table-column-group

This value declares that an element groups one or more columns. Like table-column elements, table-column-group elements are not rendered, but the value is useful for defining presentation for elements within the column group. The HTML equivalent is the colgroup element.


table-cell

This value specifies that an element represents a single cell in a table. The HTML elements th and td are both examples of table-cell elements.


table-caption

This value defines a table's caption. CSS does not define what should happen if multiple elements have the value caption, but it does explicitly warn, "...authors should not put more than one element with `display: caption' inside a table or inline-table element."

You can get a quick summary of the general effects of these values by taking an excerpt from the example HTML 4.0 style sheet given in Appendix C:

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;}

In XML, where elements will not have display semantics by default, these values become quite useful. Consider the following markup:

<scores>
  <headers>
    <label>Team</label>
    <label>Score</label>
  </headers>
  <game sport="MLB" league="NL">
    <team>
      <name>Reds</name>
      <score>8</score>
    </team>
    <team>
      <name>Cubs</name>
      <score>5</score>
    </team>
  </game>
</scores>

This could be formatted in a tabular fashion using the following styles:

scores {display: table;}
headers {display: table-header-group;}
game {display: table-row-group;}
team {display: table-row;}
label, name, score {display: table-cell;}

The various cells could then be styled as necessary—e.g., boldfacing the label elements and right-aligning the scores.

While it's theoretically possible to assign table-related display values to any HTML element, Internet Explorer does not support this capability.


11.1.2.1 Row primacy

CSS defines its table model as "row primacy." In other words, the model assumes that authors will create markup languages where rows are explicitly declared. Columns, on the other hand, are derived from the layout of the rows of cells. Thus, the first column is comprised of all the first cells in each row, the second column of the second cells, and so forth.

Row primacy is not a major issue in HTML, where the markup language is already row-oriented. In XML, it has more of an impact because it constrains the way in which authors can define table markup. Because of the row-oriented nature of the CSS table model, a markup language in which columns are the basis of table layout is not really possible (assuming that the intent is to use CSS to present such documents).

The row primacy of the CSS model will also be seen throughout the rest of the chapter as we explore the details of table presentation.

11.1.2.2 Columns

Although the CSS table model is row-oriented, columns do still play a part in layout. A cell can belong to both contexts (row and column), even if they are descended from row elements in the document source. In CSS, however, columns and column groups can accept only four styles: border, background, width, and visibility.

In addition, each of these four properties has special rules that apply only in the columnar context:


border

Borders can be set for columns and column groups only if the property border-collapse has the value collapse. In such circumstances, column and column-group borders participate in the collapsing algorithm that sets the border styles at each cell edge. (See Section 11.2.2 later in this chapter.)


background

The background of a column or column group will be visible only in cells where both the cell and its row have transparent backgrounds. (See Section 11.1.4 later in this chapter.)


width

The width property defines the minimum width of the column or column group. The content of cells within the column (or group) may force the column to become wider.


visibility

If the value of visibility for a column or column group is collapse, then none of the cells in the column (or group) are rendered. Cells that span from the collapsed column into other columns are clipped, as are cells that span from other columns into the hidden column. Furthermore, the overall width of the table is reduced by the width the column would have taken up. A declaration of any value for visibility other than hidden for a column or column group is ignored.

11.1.3 Anonymous Table Objects

There is the possibility that a markup language might not contain enough elements to fully represent tables as they are defined in CSS, or that an author will forget to include all the necessary elements. For example, consider this XHTML:

<table>
  <td>Name:</td>
  <td><input type="text"></td>
</table>

You might glance at this markup and assume that it defines a two-cell table of a single row, but structurally, there is no element defining a row (because the tr is missing).

To cover such possibilities, CSS defines a mechanism for inserting "missing" table components as anonymous objects. For a basic example of how this works, let's revisit our missing-row XHTML example. In CSS terms, what effectively happens is that an anonymous table-row object is inserted between the table element and its descendant table cells:

<table>
 [anonymous table-row object begins]
  <td>Name:</td>
  <td><input type="text"></td>
 [anonymous table-row object ends]
</table>

A visual representation of this process is given in Figure 11-2.

Figure 11-2. Anonymous object generation in table formatting
figs/css2_1102.gif

Seven different kinds of anonymous-object insertions can occur in the CSS table model. These seven rules are, like inheritance and specificity, an example of a mechanism that attempts to impose intuitive sense on the way CSS behaves.

11.1.3.1 Object insertion rules
  1. If a table-cell element's parent is not a table-row element, then an anonymous table-row object is inserted between the table-cell element and its parent. The inserted object will include all consecutive siblings of the table-cell element. Consider the following styles and markup:

    system {display: table;}
    name, moons {display: table-cell;}
    
    <system>
      <name>Mercury</name>
      <moons>0</moons>
    </system>

    The anonymous table-row object is inserted between the cell elements and the system element, and it encloses both the name and system elements.

    The same holds true even if the parent element is a table-row-group. To extend the example, assume that the following applies:

    system {display: table;}
    planet {display: table-row-group;}
    name, moons {display: table-cell;}
    
    <system>
     <planet>
      <name>Mercury</name>
      <moons>0</moons>
     </planet>
     <planet>
      <name>Venus</name>
      <moons>0</moons>
     </planet>
    </system>

    In this example, both sets of cells will be enclosed in an anonymous table-row object that is inserted between them and the planet elements.

  2. If a table-row element's parent is not a table, inline-table, or table-row-group element, then an anonymous table element is inserted between the table-row element and its parent. The inserted object will include all consecutive siblings of the table-row element. Consider the following styles and markup:

    docbody {display: block;}
    planet {display: table-row;}
    
    <docbody>
    
     <planet>
      <name>Mercury</name>
      <moons>0</moons>
     </planet>
      <planet>
      <name>Venus</name>
      <moons>0</moons>
     </planet>
    
    </docbody>

    Because the display value of the planet elements' parent is block, the anonymous table object is inserted between the planet elements and the docbody element. This object will enclose both planet elements because they are consecutive siblings.

  3. If a table-column element's parent is not a table, inline-table, or table-column-group element, then an anonymous table element is inserted between the table-column element and its parent. This is much the same as the table-row rule just discussed, except for its column-oriented nature.

  4. If the parent element of a table-row-group, table-header-group, table-footer-group, table-column-group, or table-caption element is not a table element, then an anonymous table object is inserted between the element and its parent.

  5. If a child element of a table or inline-table element is not a table-row-group, table-header-group, table-footer-group, table-row, or table-caption element, then an anonymous table-row object is inserted between the table element and its child element. This anonymous object spans all of the consecutive siblings of the child element that are not table-row-group, table-header-group, table-footer-group, table-row, or table-caption elements. Consider the following markup and styles:

    system {display: table;}
    planet {display: table-row;}
    name, moons {display: table-cell;}
    
    <system>
     <planet>
      <name>Mercury</name>
      <moons>0</moons>
     </planet>
      <name>Venus</name>
      <moons>0</moons>
    </system>

    Here, a single anonymous table-row object will be inserted between the system element and the second set of name and moons elements. The planet element is not enclosed by the anonymous object because its display is table-row.

  6. If a child element of a table-row-group, table-header-group, or table-footer-group element is not a table-row element, then an anonymous table-row object is inserted between the element and its child element. This anonymous object spans all of the consecutive siblings of the child element that are not table-row objects themselves. Consider the following markup and styles:

    system {display: table;}
    planet {display: table-row-group;}
    name, moons {display: table-cell;}
    
    <system>
     <planet>
      <name>Mercury</name>
      <moons>0</moons>
     </planet>
      <name>Venus</name>
      <moons>0</moons>
    </system>

    In this case, each set of name and moons elements will be enclosed in an anonymous table-row element. For the second set, the insertion happens in accord with Rule 5. For the first set, the anonymous object is inserted between the planet element and its children because the planet element is a table-row-group element.

  7. If a child element of a table-row element is not a table-cell element, then an anonymous table-cell object is inserted between the element and its child element. This anonymous object encloses all consecutive siblings of the child element that are not table-cell elements themselves. Consider the following markup and styles:

    system {display: table;}
    planet {display: table-row;}
    name, moons {display: table-cell;}
    
    <system>
     <planet>
      <name>Mercury</name>
      <num>0</num>
     </planet>
    </system>

    Because the element num does not have a table-related display value, an anonymous table-cell object is inserted between the planet element and the num element.

    This behavior also extends to the encapsulation of anonymous inline boxes. Suppose that the num element was not included:

    <system>
     <planet>
      <name>Mercury</name>
      0
     </planet>
    </system>

    The 0 would still be enclosed in an anonymous table-cell object. To further illustrate this point, here is an example adapted from the CSS specification:

    example {display: table-cell;}
    row {display: table-row;}
    hi {font-weight: 900;}
    
    <example>
      <row>This is the <hi>top</hi> row.</row>
      <row>This is the <hi>bottom</hi> row.</row>
    </example>

    Within each row element, the text fragments and hi element are enclosed in an anonymous table-cell object.

11.1.4 Table Layers

For the assembly of a table's presentation, CSS defines six individual "layers" on which the various aspects of a table are placed. Figure 11-3 shows these layers.

Figure 11-3. The formatting layers used in table presentation
figs/css2_1103.gif

Basically, the styles for each aspect of the table are drawn on their individual layers. Thus, if the table element has a green background and a 1-pixel black border, then those styles are drawn on the lowest layer. Any styles for the column groups are drawn on the next layer up, the columns themselves on the layer above that, and so on. The top layer, which corresponds to the table cells, is drawn last.

For the most part, this is simply a logical process; after all, if you declare a background color for table cells, you would want that drawn over the background for the table element. The most important point revealed by Figure 11-3 is that column styles come below row styles, so a row's background will overwrite a column's background.

It is important to remember that, by default, all elements have transparent backgrounds. Thus, in the following markup, the table element's background will be visible "through" cells, rows, columns, and so forth that do not have a background of their own, as illustrated in Figure 11-4:

<table style="background: #888;">
 <tr>
  <td>hey</td>
  <td style="background: #CCC;">there</td>
 </tr>
<tr>
  <td>what's</td>
  <td>up?</td>
 </tr>
<tr style="background: #AAA;">
  <td>tiger</td>
  <td style="background: #CCC;">lilly</td>
 </tr>
</table>
Figure 11-4. Seeing the background of table-formatting layers through other layers
figs/css2_1104.gif

11.1.5 Captions

A table caption is about what you'd expect: a short bit of text that describes the nature of the table's contents. A chart of stock quotes for the fourth quarter of 2003, therefore, might have a caption element whose contents read "Q4 2003 Stock Performance." With the property caption-side, you can place this element either above or below the table, regardless of where the caption appears in the table's structure. (In HTML, the caption element can appear only after the opening table element, but other languages may have different rules.)

caption-side


Values

top | bottom


Initial value

top


Applies to

elements with the display value table-caption


Inherited

no


Computed value

as specified


Note

the values left and right appeared in CSS2 but were dropped from CSS2.1 due to a lack of widespread support


Captions are a bit odd, at least in visual terms. The CSS specification states that a caption is formatted as if it were a block box placed immediately before (or after) the table's box, with a couple of exceptions. The first is that the caption can still inherit values from the table, and the second is that a user agent ignores a caption's box when considering what to do with a run-in element that precedes the table. Therefore, a run-in element that comes before a table will not run into a top caption, nor into the table, but will instead be treated as if its display value were block.

A simple example should suffice to illustrate most of the important aspects of caption presentation. Consider the following, illustrated in Figure 11-5:

caption {background: gray; margin: 1em 0;
  caption-side: top;}
table {color: white; background: black; margin: 0.5em 0;}
Figure 11-5. Styling captions and tables
figs/css2_1105.gif

The text in the caption element inherits the color value white from the table, while the caption gets its own background. The separation between the table's outer border edge and the caption's outer margin edge is one em, as the top margin of the table and bottom margin of the caption have collapsed, as described in Chapter 7. Finally, the width of the caption is based on the content width of the table element, which is considered to be the containing block of the caption. These same results would occur if you change the value of caption-side to bottom, except that the caption would be placed after the table's box, and collapsing would occur between the top margin of the caption and the bottom margin of the table.

For the most part, captions are styled just like any block-level element; they can be padded, have borders, be given backgrounds, and so on. For example, if you need to change the horizontal alignment of text within the caption, you use the property text-align. Thus, to right-align the caption in the previous example, you would write:

caption {background: gray; margin: 1em 0;
  caption-side: top; text-align: right;}
    Previous Section  < Day Day Up >  Next Section