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

11.3 Table Sizing

Now that we've dug into the guts of table formatting and cell border appearance, we have the pieces we need to understand the sizing of tables and their internal elements. When it comes to determining table width, there are two different approaches: fixed-width layout and automatic-width layout. Heights are calculated automatically no matter what width algorithms are used.

11.3.1 Width

Since there are two different ways to figure out the width of a table, it's only logical that there be a way to declare which should be used for a given table. Authors can use the property table-layout to select between the two kinds of table width calculation.

table-layout


Values

auto | fixed | inherit


Initial value

auto


Applies to

elements with the display value table or inline-table


Inherited

yes


Computed value

as specified


While the two models can have different results in laying out a specific table, the more fundamental difference between the two is that of speed. With a fixed-width table layout, the user agent can calculate the layout of the table more quickly than is possible in the automatic-width model.

11.3.1.1 Fixed layout

The main reason the fixed-layout model is so fast is that its layout does not depend on the contents of table cells. Instead, it's driven by the width values of the table, columns, and cells within that table.

The fixed-layout model works in the following simple steps:

  1. Any column element whose width property has a value other than auto sets the width for that column.

  2. If a column has an auto width, but the cell in the first row of the table within that column has a width other than auto, then the cell sets the width for that column. If the cell spans multiple columns, then the width is divided between the columns.

  3. Any columns that are still auto-sized are sized so that their widths are as equal as possible.

At that point, the width of the table is set to be either the value of width for the table or the sum of the column widths, whichever is greater. If the table turns out to be wider than its columns, then the difference is divided by the number of columns and added to each of them.

This approach is fast because all of the column widths are defined by the first row of the table. The cells in any rows that come after the first are sized according to the column widths that were defined by the first row. The cells in those following rows do not change column widths, which means that any width value assigned to those cells will be ignored. In cases where a cell's content does not fit into its cell, the overflow value for the cell determines whether the cell contents are clipped, visible, or generate a scrollbar.

Let's consider the following styles and markup, which are illustrated in Figure 11-11:

table {table-layout: fixed; width: 400px;
  border-collapse: collapse;}
td {border: 1px solid;}
col#c1 {width: 200px;}
#r1c2 {width: 75px;}
#r2c3 {width: 500px;}

<table>
<colgroup>
<col id="c1"><col id="c2"><col id="c3"><col id="c4">
</colgroup>
<tr>
<td id="r1c1">1-1</td><td id="r1c2">1-2</td>
<td id="r1c3">1-3</td><td id="r1c4">1-4</td>
</tr>
<tr>
<td id="r2c1">2-1</td><td id="r2c2">2-2</td>
<td id="r2c3">2-3</td><td id="r2c4">2-4</td>
</tr>
<tr>
<td id="r3c1">3-1</td><td id="r3c2">3-2</td>
<td id="r3c3">3-3</td><td id="r3c4">3-4</td>
</tr>
<tr>
<td id="r4c1">4-1</td><td id="r4c2">4-2</td>
<td id="r4c3">4-3</td><td id="r4c4">4-4</td>
</tr>
</table>
Figure 11-11. Fixed-width table layout
figs/css2_1111.gif

As you can see in Figure 11-11, the first column is 200 pixels wide, which happens to be half the 400-pixel width of the table. The second column is 75 pixels wide because the first-row cell within that column has been assigned an explicit width. The third and fourth columns are each 61 pixels wide. Why? Because the sum of the column widths for the first and second columns (275px), plus the various borders between columns (3px), equals 278 pixels. 400 minus 278 is 122, and that divided in half is 61, so that's how many pixels wide the third and fourth columns will be. What about the 500-pixel width for #r2c3? It's ignored because that cell isn't in the first row of the table.

Note that it is not absolutely necessary that the table have an explicit width to make use of the fixed-width layout model, although it definitely helps. For example, given the following, a user agent could calculate a width for the table that is 50 pixels narrower than the parent element's width. It would then use that calculated width in the fixed-layout algorithm:

table {table-layout: fixed; margin: 0 25px;
  width: auto;}

This is not required, however. User agents are also permitted to lay out any table with an auto value for width using the automatic-width layout model.

11.3.1.2 Automatic layout

The automatic-layout model, while not as fast as fixed layout, is probably much more familiar to you because it's substantially the same model that HTML tables have used for years. In most current user agents, use of this model will be triggered by a table having a width of auto, regardless of the value of table-layout, although this is not assured.

The reason automatic layout is slower is that the table cannot be laid out until the user agent has looked at all of the content of the table. That is, it requires that the user agent lay out the entire table each time it gets a new cell. This generally requires the user agent to perform some calculations and then go back through the table to perform a second set of calculations. The content has to be fully examined because, as with HTML tables, the table's layout is dependent on the content in all the cells. If there is a 400-pixel-wide image in a cell in the last row, then it will force all of the cells above it (those in the same column) to be 400 pixels wide. Thus, the width of every cell has to be calculated, and adjustments must be made (possibly triggering another round of content-width calculations) before the table can be laid out.

The details of the model can be expressed in the following steps:

  1. For each cell in a column, calculate both the minimum and maximum cell width.

    1. Determine the minimum width required to display the content. In determining this minimum content width, the content can flow to any number of lines, but it may not stick out of the cell's box. If the cell has a width value that is larger than the minimum possible width, then the minimum cell width is set to the value of width. If the cell's width value is auto, then the minimum cell width is set to the minimum content width.

    2. For the maximum width, determine the width required to display the content without any line breaking other than that forced by explicit line breaking (e.g., the <br> element). That value is the maximum cell width.

  2. For each column, calculate both the minimum and maximum column width.

    1. The column's minimum width is determined by the largest minimum cell width of the cells within the column. If the column has been given an explicit width value that is larger than any of the minimum cell widths within the column, then the minimum column width is set to the value of width.

    2. For the maximum width, take the largest maximum cell width of the cells within the column. If the column has been given an explicit width value that is larger than any of the maximum cell widths within the column, then the maximum column width is set to the value of width. These two behaviors recreate the traditional HTML table behavior of forcibly expanding any column to be as wide as its widest cell.

  3. In cases where a cell spans more than one column, then the sum of the minimum column widths must be equal to the minimum cell width for the spanning cell. Similarly, the sum of the maximum column widths has to equal the spanning cell's maximum width. User agents should divide any changes in column widths equally among the spanned columns.

In addition, the user agent must take into account that when a column width has a percentage value for its width, the percentage is calculated in relation to the width of the table—even though it doesn't yet know what that will be! It instead has to hang on to the percentage value and use it in the next part of the algorithm.

At this point, the user agent will have figured how wide or narrow each column can be. With that information in hand, it can then proceed to actually figuring out the width of the table. This happens as follows:

  1. If the computed width of the table is not auto, then the computed table width is compared to the sum of all the column widths plus any borders and cell spacing. (Columns with percentage widths are likely calculated at this time.) The larger of the two is the final width of the table. If the table's computed width is larger than the sum of the column widths, borders, and cell spacing, then all columns are increased in width by an equal amount until they all fit into the table.

  2. If the computed width of the table is auto, then the final width of the table is determined by adding up the column widths, borders, and cell spacing. This means that the table will be only as wide as needed to display its content, just as with traditional HTML tables. Any columns with percentage widths use that percentage as a constraint—but one that a user agent does not have to satisfy.

Once the last step is completed, then, and only then, can the user agent actually lay out the table.

The following styles and markup, presented in Figure 11-12, help illustrate how this process works:

table {table-layout: auto; width: auto;
  border-collapse: collapse;}
td {border: 1px solid;}
col#c3 {width: 25%;}
#r1c2 {width: 40%;}
#r2c2 {width: 50px;}
#r2c3 {width: 35px;}
#r4c1 {width: 100px;}
#r4c4 {width: 1px;}

<table>
<colgroup>
<col id="c1"><col id="c2"><col id="c3"><col id="c4">
</colgroup>
<tr>
<td id="r1c1">1-1</td><td id="r1c2">1-2</td>
<td id="r1c3">1-3</td><td id="r1c4">1-4</td>
</tr>
<tr>
<td id="r2c1">2-1</td><td id="r2c2">2-2</td>
<td id="r2c3">2-3</td><td id="r2c4">2-4</td>
</tr>
<tr>
<td id="r3c1">3-1</td><td id="r3c2">3-2</td>
<td id="r3c3">3-3</td><td id="r3c4">3-4</td>
</tr>
<tr>
<td id="r4c1">4-1</td><td id="r4c2">4-2</td>
<td id="r4c3">4-3</td><td id="r4c4">4-4</td>
</tr>
</table>
Figure 11-12. Automatic table layout
figs/css2_1112.gif

Let's consider what happened for each of the columns, in turn:

  • For the first column, the only explicit cell or column width is that of cell 4-1, which was given a width of 100px. Because the content is so short, the minimum and maximum column width becomes 100px. (If there were a cell in the column with several sentences of text, it would have increased the maximum column width to whatever width necessary to display all of the text without line-breaking.)

  • For the second column, two widths were declared: cell 1-2 was given a width of 40%, and cell 2-2 was given a width of 50px. The minimum width of this column is 50px, and the maximum width is 40% of the final table width.

  • For the third column, only cell 3-3 had an explicit width (35px), but the column itself was given a width of 25%. Therefore, the minimum column width is 35px, and the maximum width is 25% the final table width.

  • For the fourth column, only cell 4-4 was given an explicit width, that of 1px. This is smaller than the minimum content width, so both the minimum and maximum column widths are equal to the minimum content width of the cells. This turns out to be a computed 25 pixels.

The user agent now knows that the four columns have minimum and maximum widths as follows:

  1. min 100px / max 100px

  2. min 50px / max 40%

  3. min 35px / max 25%

  4. min 25px / max 25px

Thus, the table's minimum width is the sum of all the column minima plus the borders, which totals 215 pixels. The table's maximum width is 130px + 65%, which works out to be 371.42857143 pixels (given that 130px represents 35% of the overall table width). Let's assume this to be, after rounding the fractional number off to 371 pixels, the width value user agents will actually use. Thus, the second column will be 148 pixels wide, and the third column will be 93 pixels wide. It is not required that user agents actually use the maximum value; they may choose another course of action.

Of course, this was (although it may not seem like it) a very simple and straightforward example: all of the content was basically the same width, and most of the declared widths were pixel lengths. In a situation where a table contains spacer GIFs, paragraphs of text, form elements, and so forth, the process of figuring out the table's layout is likely to be a great deal lengthier.

11.3.2 Height

After all of the effort that was expended in figuring out the width of the table, you might well wonder how much more complicated height calculation will be. Actually, in CSS terms, it's pretty simple, although browser developers probably don't think so.

The easiest situation to describe is one in which the height is explicitly set via the height property. In such cases, the height of the table is defined by the value of height. This means that a table may be taller or shorter than the sum of its row heights. In such cases, the CSS2.1 specification explicitly refuses to define what should happen, instead noting that the issue may be resolved in future versions of CSS. A user agent could expand or shrink a table's rows to match its height, or implement a scrollbar to get to overflowing rows, or neither, or something completely different. It's up to each user agent to decide.

If the height of the table is auto, then its height is the sum of the heights of all the rows within the table, plus any borders and cell spacing. To determine the height of each row, the user agent goes through a process similar to that used to find the widths of columns. It calculates a minimum and maximum height for the contents of each cell and then uses these to derive a minimum and maximum height for the row. After having done this for all the rows, the user agent figures out what each row's height should be, stacks them all on top of each other, and uses that calculation to determine the table's height. It's a lot like inline layout, only with less certainty in how things should be done.

In addition to what to do about tables with explicit heights and how to treat row heights within them, you can add the following to the list of things CSS2.1 does not define:

  • The effect of a percentage height for table cells.

  • The effect of a percentage height for table rows and row groups.

  • How a row-spanning cell affects the heights of the rows that are spanned, except that the rows have to contain the spanning cell.

As you can see, height calculations in tables are largely left up to user agents to figure out. Historical evidence would suggest that this will lead to each user agent doing something different, so you should probably avoid setting heights as much as possible.

11.3.3 Alignment

In a rather interesting turn of events, alignment of content within cells is a lot better defined than cell and row heights. This is true even for vertical alignment, which could quite easily affect the height of a row.

Horizontal alignment is the simplest. To align content within a cell, you use the text-align property. In effect, the cell is treated as a block-level box and all of the content within it is aligned as per the text-align value. (For details on text-align, see Chapter 6.)

To vertically align content in a table cell, vertical-align is the relevant property. It uses many of the same values that are used for vertically aligning inline content, but the meanings of those values change when applied to a table cell. To summarize the three simplest cases:


top

The top of the cell's content is aligned with the top of its row; in the case of row-spanning cells, the top of the cell's content is aligned with the top of the first row it spans.


bottom

The bottom of the cell's content is aligned with the bottom of its row; in the case of row-spanning cells, the bottom of the cell's content is aligned with the bottom of the last row it spans.


middle

The middle of the cell's content is aligned with the middle of its row; in the case of row-spanning cells, the middle of the cell's content is aligned with the middle of all the rows it spans.

These are illustrated in Figure 11-13, which uses the following styles and markup:

table {table-layout: auto; width: 20em;
  border-collapse: separate; border-spacing: 3px;}
td {border: 1px solid; background: silver;
  padding: 0;}
div {border: 1px dashed gray; background: white;}
#r1c1 {vertical-align: top; height: 10em;}
#r1c2 {vertical-align: middle;}
#r1c3 {vertical-align: bottom;}

<table>
<tr>
<td id="r1c1">
<div>
The contents of this cell are top-aligned.
</div>
</td>
<td id="r1c2">
<div>
The contents of this cell are middle-aligned.
</div>
</td>
<td id="r1c3">
<div>
The contents of this cell are bottom-aligned.
</div>
</td>
</tr>
</table>
Figure 11-13. Vertical alignment of cell contents
figs/css2_1113.gif

In each case, the alignment is carried out by automatically increasing the padding of the cell itself to achieve the desired effect. In the first cell in Figure 11-13, the bottom padding of the cell has been changed to equal the difference between the height of the cell's box and the height of the content within the cell. For the second cell, the top and bottom padding of the cell have been reset to be equal, thus vertically centering the content of the cell. In the last cell, the cell's top padding has been altered.

The fourth possible value alignment is baseline, and it's a little more complicated that the first three:


baseline

The baseline of the cell is aligned with the baseline of its row; in the case of row-spanning cells, the baseline of the cell is aligned with the baseline of the first row it spans.

It's easiest to provide an illustration (see Figure 11-14) and then discuss what's happening.

Figure 11-14. Baseline alignment of cell contents
figs/css2_1114.gif

A row's baseline is defined by the lowest initial cell baseline (that is, the baseline of the first line of text) out of all its cells. Thus, in Figure 11-14, the row's baseline was defined by the third cell, which has the lowest initial baseline. The first two cells then have a baseline of their first line of text aligned with the row's baseline.

As with top, middle, and bottom alignment, the placement of baseline-aligned cell content is accomplished by altering the top and bottom padding of the cells. In cases where none of the cells in a row are baseline-aligned, the row does not even have a baseline—it doesn't really need one.

The detailed process for aligning cell contents within a row is as follows:

  1. If any of the cells is baseline-aligned, then the row's baseline is determined and the content of the baseline-aligned cells is placed.

  2. Any top-aligned cell has its content placed. The row now has a provisional height, which is defined by the lowest cell bottom of the cells that have already had their content placed.

  3. If any remaining cells are middle- or bottom-aligned, and the content height is taller than the provisional row height, the height of the row is increased to enclose the tallest of those cells.

  4. All remaining cells have their content placed. In any cell whose contents are shorter than the row height, the cell's padding is increased in order to match the height of the row.

The vertical-align values sub, super, text-top, and text-bottom are ignored when applied to table cells. Thus, the following rule would have the same result as that shown in Figure 11-14:

th {vertical-align: text-top;}
    Previous Section  < Day Day Up >  Next Section