Table Formatting

    Adam Roberts
    Share

    Tables are the most complex elements in HTML, and table formatting is among the most complex parts of CSS. CSS defines a number of objects that are involved in table formatting, as the below image reveals.

    Table formatting objects

    Table formatting objects

    A table may contain a caption, row groups, and column groups. A row group contains rows, while a column group contains columns. Rows and columns contain cells. Tables are rendered as layers in a specified order from the bottom up: table, column groups, columns, row groups, rows, and cells.

    The table model in HTML is row-centric. Although you can specify columns and column groups in markup, cells are structurally contained within rows. Columns and column groups are more esoteric items that are derived from the set of cells in all rows of the table.

    A table can be included in a formatting context as either a block-level or inline-level box. It can have padding, borders, and margins.

    A table element generates an anonymous box that encompasses the table box and the caption box (if they’re present). The caption box is rendered outside the table box, but is inextricably tied to it. When a table is repositioned, it’s the outer anonymous box that’s moved to enable the caption to follow the table.

    Captions inherit inheritable properties from the table. A caption is formatted as a block box, but it doesn’t behave like general block boxes in all respects. If a run-in element precedes the table, it will not run into a caption box.

    The placement of the caption can be controlled via the caption-side property. The valid values in CSS2.1 are top and bottom, which should be fairly self-explanatory.

    The internal elements of tables—row groups, column groups, rows, columns, and cells—generate regular boxes that can have borders. Cells can also have padding, but internal table objects don’t have margins.

    Ten of the valid values for the display property denote table-related formatting styles. These values, and the HTML element types with which they’re associated by default, are shown in the below table.

    Table 1. Table display Property Values
    Element Type Property Value HTML Element
    Table table table
    inline-table n/a
    Caption table-caption caption
    Row group table-header-group thead
    table-footer-group tfoot
    table-row-group tbody
    Row table-row tr
    Column group table-column-group colgroup
    Column table-column col
    Cell table-cell td
    th

    These display values can also be specified for other element types than those that belong to the HTML table model; however, Internet Explorer versions up to and including 7 don’t support these values.

    When table-related display values are used for non-table elements, anonymous table-related elements may have to be generated in order to render the elements correctly. Here, we’ve listed situations in which anonymous table-related elements may be created:

    • Cells must have a row as their parent. A row object will be
      generated as the parent of one or more consecutive cells that don’t have
      a row as their parent.
    • Rows must have a row group or a table as their parent. Columns must
      have a column group or a table as their parent. Row groups and column
      groups must have a table as their parent. A table object will be
      generated as the parent of one or more consecutive objects of those
      types that don’t have the required parent.
    • If a child of a table object is not a caption, row group, column
      group, row, or column, a row object will be generated as the parent of
      that child, and any consecutive siblings that require a row as their
      parent.
    • If a child of a row group object isn’t a row, a row object will be
      generated as the parent of that child and any consecutive siblings that
      require a row as their parent.
    • If a child of a row object is not a cell, a cell object will be
      generated as the parent of that child and any consecutive siblings that
      are not cells.

    Properties that Apply to Column and Column-group Elements

    Only a few properties can be applied to elements with a display property value of table-column or table-column-group:

    • the border properties, but only in the
      collapsing borders model (see below)
    • the background properties, where cells and rows
      have transparent backgrounds
    • the width property
    • the visibility property value
      collapse—any other visibility values are ignored
      for columns and column groups

    Table Width Algorithms

    Unlike other block boxes, a table with zero horizontal margins and a width property that’s set to auto doesn’t size to fill its containing block. Instead, the table size will be determined by its contents. A table can be horizontally centered by setting margin-left and margin-right to auto, though.

    There are two very different algorithms for determining the widths of table columns: the fixed table layout algorithm and the automatic table layout algorithm. These are specified with the table-layout property (which takes values of fixed, for fixed layouts, and auto, for automatic layouts); its initial value is auto. If the table’s width is specified as auto, the automatic table layout algorithm is normally used. In the case of block-level tables (when display is set to table), user agents are allowed to use the fixed table layout algorithm anyway, but they aren’t required to.

    With the fixed table layout algorithm, the widths of columns and of the table are not governed by the contents of the table’s cells. Instead, the width of each column is determined as follows:

    • Column objects whose width is not
      auto set the width for that column.
    • A cell in the first row, whose width is not
      auto, sets the width of the column it belongs to.
      If the cell spans more than one column, the width is divided over the
      columns.
    • Any remaining columns equally divide the remaining horizontal
      space, minus any borders or cell spacing.

    The width of the table is the greater of the value of the table’s width property, and the sum of the column widths (plus borders or cell spacing). If the table is wider than the columns, the extra space will be distributed over the columns.

    Don’t Omit Cells!

    Since the cells in the first row of the table are used to determine the column widths, you shouldn’t omit any cells from the first row if you use the fixed table layout algorithm. The behavior in such case is undefined by the CSS2.1 specification.

    The automatic table layout algorithm usually requires more than one pass. The CSS2.1 specification suggests an algorithm for determining column widths, but user agents are not required to use it.

    The suggested algorithm for determining column widths examines every cell in the entire table, computing the minimum and maximum widths required for rendering each cell. These values are then used to determine how wide each column should be, which in turn may decide the width of the table itself.

    Performance and Automatic Table Layouts

    Since every single cell must be inspected, the automatic table layout algorithm can become very time-consuming when it’s calculated for a table with a large number of rows and/or columns.

    Table Height Algorithms

    If the table’s height property has a value other than auto, and the specified height differs from the sum of the row heights plus borders or cell spacing, the behavior is undefined.

    Percentage values for the height property are undefined for rows, row groups, and cells.

    The vertical-align property of each cell determines its alignment within the row. Only the values baseline, top, bottom, and middle are allowed. For any other value, baseline will be used.

    Borders On Table Objects

    There are two different models in CSS2 for rendering borders around internal table objects: the separated borders model and the collapsing borders model. We can choose the model we prefer by using the border-collapse property, and setting the value to separate (the initial value) or collapse.

    In the separated borders model only cells (and the table itself) can have borders; rows, row groups, columns, and column groups cannot. Borders are drawn individually around the cells and the cells are separated by the vertical and horizontal distances specified by the border-spacing property. In the space between cell borders, the backgrounds of rows, row groups, columns, and column groups are invisible. Only the table background is visible in the inter-cell spacing. The below image shows an example of a table that’s rendered using the separated borders model.

    Rendering a table with separated borders

    Rendering a table with separated borders

    Here’s the relevant CSS for the table:

    table {
      border-collapse: separate;
      border-spacing: 1em 0.5em;
      background-color: #ddd;
    }

    Another property that applies in the separated borders model is the empty-cells property. It controls whether cells that lack visible content have borders and backgrounds (if the value is show, the initial value) or not (if the value is hide). Carriage returns, line feeds, tabs, and blanks are not considered to be visible content, although a non-breaking space is.

    In the collapsing borders model, the cells aren’t separated from one another and their borders—along with borders of rows, row groups, columns, column groups and the table itself—collapse (or overlap) in a rather complicated way. An example of a table to which the collapsing borders model is applied is shown here:

    Rendering a table with collapsed borders

    Rendering a table with collapsed borders

    With this model, quite a few borders may be specified in such a way that they would be rendered in the same place. The CSS2.1 specification provides an algorithm for border conflict resolution—that is, which border will win, or be rendered, in these situations. Very broadly speaking, the most eye-catching border will be rendered, unless at least one of the borders has border-style set to hidden, in which case no border will be rendered.

    If none of the borders are hidden, wide borders win over narrow borders. If two or more borders have the same width, the border-style property decides which one will be rendered. The styles are preferred in the following order: double, solid, dashed, dotted, ridge, outset, groove, and inset. Borders with border-style set to none have the lowest priority, and will never win over other border styles—even if they have a large width value.

    If there is still no winner, the algorithm looks at the objects for which the borders are set. The preferred order is: cell, row, row group, column, column group, and table.

    The border-spacing and empty-cells properties are ignored when the collapsing borders model is used.