CSS tables performance

Tables can be a real bottleneck in the overall page loading because browsers parse and render them in a peculiar way. When a table has an automatic width (table-layout: auto), browsers must perform a different calculation on each row and cell to determine what is the actual width of the table itself. Since the overall width of a table is given by the sum of the widths of its cells, it's safe to say that with an automatic table layout browsers don't know in advance how to calculate these widths.

Instead, with a fixed table layout (table-layout: fixed) such calculations are much faster, because the fixed table layout algorithm has the obvious advantage of being clearly defined in the CSS specifications, while the automatic layout mostly relies on browser's internal algorithms.

In short, use this:

table {
  table-layout: fixed;
}

It's not necessary to specify a width for the table cells. The important thing here is that you're actually forcing the browser to use a fixed table algorithm.

Table headers and text alignment in CSS

Bruno Fassino wrote this note:

Table headers (th) have a default center text alignment in most browsers.

Appendix D of the CSS2.1 spec suggests a

th { text-align: center }

rule in the default UA style sheet. But not all browsers get the above alignment in such a way, as demonstrated by what follows.

The following test case has text-align: left added to the row element (tr) including the th.

If an UA had the rule (1) in its default sheet, than the above test case should not display differently from the first one, even if text-align is a property which "inherits", because when a property is "directly" applied to an element, then inheritance does not trigger. See CSS 2.1 section 6.1.1: inheritance is taken into account only if the cascade does not result in a value (in other words: inheritance has always less "precedence" than a specified value in the cascade).

So, according to the above, with a rule (1) in the UA sheet any text-align applied on an ancestor of a th should have no effect on the th. In IE8 indeed the rendering of the above two test cases is the same. However, most other browsers (Firefox, Opera, Safari, IE<8), probably for compatibility with existing pages, behave in a way that text-align applied to an ancestor of a th has an effect on the th itself. This means that they behave differently than having a rule (1) in their UA sheet. This behavior is probably not expressible in terms of standard existing CSS properties and values.

A bug filed for Gecko, about it allowing text-align on a parent to "override" the centering of a th, has been marked as invalid. Appendix D is indeed not normative, so browsers are not required to behave exactly in that way.

CSS tables: the CSS table model

The CSS table model is build upon the HTML 4.0 table model, where the structure of a table resembles its visual layout. This model is said to be a row supremacy model, because authors explicitly specify table rows in the source code. The CSS table model consists of tables (table), captions (caption), rows (tr), row groups (tbody), columns (col), column groups (colgroup) and cells (td, th).

For those languages (such as XML) which don't have predefined table elements, authors must use the following values of the display property:

  • table

    Specifies a block-level table.

  • inline-table

    Specifies an inline table.

  • table-row

    Specifies a table row.

  • table-row-group

    Just like tbody.

  • table-header-group

    Just like thead.

  • table-footer-group

    Just like tfoot.

  • table-column

    Just like col.

  • table-column-group

    Just like colgroup.

  • table-cell

    Just like td/th.

  • table-caption

    Just like caption.

Columns

The following properties apply to columns and column groups:

  • border

    Only if border-collapse is set to collapse on the table.

  • background

    It applies only if cells and rows have transparent backgrounds.

  • width

    This property gives the minimum width to the column.

  • visibility

    The only value that works is collapse. In this case, no cell is rendered.

Table algorithms

Through the table-layout property you can choose either a fixed or an automatic table layout algorithm. With the first, the table layout doesn't depend on the content of its single cells, but only on the overall width of the table, the overall width of the columns and the spacing between borders and cells. The width of the table can be specified via the width property. If you specify an auto value, it implies that you're actually using an automatic algorithm.

With the latter, instead, the width of the table is determined by the width of columns and borders. The CSS specifications allow browsers to use whatever other algorithm they want, even if the results may be different. In practice, however, the table width is determined by the amount of content it contains.

JavaScript manipulation

From a performance perspective, it's better to build a table using the innerHTML property, which is considerably faster than traditional DOM methods. Anyway, if you want to use a DOM approach, bear in mind that Internet Explorer 6 and 7 have significant problems with the createElement() and appendChild() methods when applied to tables.

CSS floats or tables? A practical approach

I'm going to develop a web-based application for domestic use containing a database for all our DVDs. In that vein, I'd like to mention here a little problem occurred during the creation process of the markup used for displaying search results. The question is: floats or tables? Since I have to deal with items like director, year, actors and so on, using floats actually involves a markup like the following:

<ul class="dvd-info">
<li>
  <div class="dvd-item">
    <h4>Director</h4>
  </div>
  <div class="dvd-content">
    <p>Ridley Scott</p>
  </div>
</li>
<!-- more items here -->
</ul>

The CSS would be something like:

ul.dvd-info {
  width: 100%;
  margin: 0 0 0.4em 0;
  padding: 0;
  list-style: none;
}
ul.dvd-info li {
  height: 100%;
  overflow: hidden;
  margin-bottom: 4px;
}

ul.dvd-info li .dvd-item {
  float: left;
  width: 25%;
  text-align: right;
}
ul.dvd-info li .dvd-content {
  float: left;
  width: 70%;
  padding-left: 0.3em;
}

The problem with this approach is that we're actually dealing with a semantic relationship between items (e.g. "Director" and "Ridley Scott") that will be completely lost if we use the aforementioned markup and floats. In fact, we should use a table heading associated with a table cell. This approach also makes our content easier to navigate for assistive technologies that use keyboard shortcuts to extract and navigate page contents. In this case, I think, using a table is the right choice.