Learning HTML 3.2 by Examples, section 4 Fundamental structures in HTML 3.2, with examples:

Tables (Not in HTML 2.0!)

Index:

The table concept in HTML 3.2

In HTML, a table is a structure consisting of rows and columns, which can have headers (names, titles, explanations). A table is typically rendered in some natural way corresponding to the structure, with columns adjusted accordingly. The components, or cells, of a table may contain any text elements or even block elements and headings. Thus, a table cell might contain a number, a word, a text paragraph, an image, or something more complicated.

Table cells are often called table elements, but it is best to avoid that in the HTML context, since it might cause confusion e.g. with the TABLE element, which is the HTML description of an entire table.

Tables are the most important improvement in HTML 3.2 in comparison with HTML 2.0. On the other hand, the table constructs of HTML 3.2 are only a subset of the draft The HTML3 Table Model (RFC 1942).

Tables are supported by most browsers, but there are many problems with the support, especially if you use large and complicated tables.

Text-only browsers and speech-based user agents will always have difficulties with complicated tables, for obvious reasons. See Alan Flavell's review Tables on non-table browser for information about making tables look somewhat reasonable, if possible, also on browsers which do not support tables. See also Web Accessibility Initiative.

Authors often use table elements just to get a desired layout of pages, not to represent data which is logically matrix-like in structure. This reduces accessibility and causes other problems. The HTML 4.0 specification explicitly says that "tables should not be used purely as a means to layout document". For detailed arguments, see e.g. Tables in Dan's Web Tips.

Tags used to represent tables

Representing a table involves several kinds of HTML tags:

The very basic table structure

Let us start with a very simple example. It consists of a 2 by 2 table of numbers (a unit matrix), with no headers whatsoever. The HTML code is as follows:

Example table1.html:

<TABLE>
<TR> <TD> 1 </TD> <TD> 0 </TD> </TR>
<TR> <TD> 0 </TD> <TD> 1 </TD> </TR>
</TABLE>
and it looks like the following on a typical browser:

1 0
0 1

Thus, the TABLE tags enclose the table rows, each of which is enclosed by TR tags and enclose table cells enclosed by TD tags. This corresponds to the logical structure of a table as a set of rows consisting of cells. You can abbreviate the table structure by omitting the TD and TR end tags (since a browser implicitly assumes them), but at the expense of losing the logical clarity to some extent:

<TABLE>
<TR> <TD> 1 <TD> 0
<TR> <TD> 0 <TD> 1
</TABLE>

Moreover, although omitting those end tags is legal HTML 3.2, it may in practise confuse some browsers (including Netscape) in some cases.

According to the specifications, the use of blanks and newlines in the HTML code for a table is irrelevant to the visual appearance of a table when viewed with a browser, since that appearance is controlled by HTML tags. However, it is often useful to position table elements suitably in the HTML code so that items in the same column are adjusted to make the structure clear for you (or whoever has to maintain the HTML document). On the other hand, Netscape is known to violate the specifications: blanks or newlines between tags may affect the presentation (causing, for example, extra space between the content of a cell and its border)

Additional features; a typical table with text cells

There are several separate features which you will often like to add to this simple table model: The following, rather typical, example uses all of the above-mentioned features:

Example table2.html:

<P>An illustration of the use of the TABLE element in HTML.</P>
<TABLE BORDER=1>
<CAPTION>Finnish, English, and scientific names for some animals</CAPTION>
<TR><TH>Finnish name</TH><TH>English name</TH><TH>Scientific name</TH></TR>
<TR><TD>hirvi</TD><TD>elk</TD><TD><I>Alces alces</I></TD></TR>
<TR><TD>orava</TD><TD>squirrel</TD><TD><I>Sciurus vulgaris</I></TD></TR>
<TR><TD>susi</TD><TD>wolf</TD><TD><I>Canis lupus</I></TD></TR>
</TABLE>
Notice that some table elements in the example contain text markup; in this case, there is a specific reason for using the I element.

Parallel texts

If you have logically parallel texts, such as a document in several languages or several variants of the same text, the TABLE element is probably the best way of presenting them. (Using a PRE element is possible but requires tedious formatting by hand and results in the text being displayed in monospaced font.)

In the simplest case you can just write a TABLE element (with attributes defaulted) which contains a single row which contains two data cells, each of which contains a paragraph.

In a more general case, you should divide the parallel texts into logical parts, such as paragraphs, and make each part a cell of the table. This may require a lot of work (unless you have a suitable program to do the job), since you must take care of "merging" the text: after the first part of the first text, you must have the first part of the second text, etc.

The following example presents a passage from the Bible in three versions and translations:

Example table3.html:

<TABLE>
<CAPTION><STRONG>The beginning of Genesis
in three languages</STRONG></CAPTION>
<TR ALIGN=LEFT VALIGN=TOP>
<TH></TH><TH>Latin (Vulgate)</TH><TH>English (King James version)</TH>
<TH>Finnish (1992 version)</TH>
</TR><TR ALIGN=LEFT VALIGN=TOP>
<TH>1</TH>
<TD>In principio creavit Deus caelum et terram.</TD>
<TD>In the beginning God created the heaven and the earth.</TD>
<TD>Alussa Jumala loi taivaan ja maan.</TD>
</TR><TR ALIGN=LEFT VALIGN=TOP>
<TH>2</TH>
<TD>Terra autem erat inanis et vacua et tenebrae super faciem
abyssi et spiritus Dei ferebatur super aquas.</TD>
<TD>And the earth was without form, and void;
and darkness was upon the face of the deep.
And the Spirit of God moved upon the face
of the waters.</TD>
<TD>Maa oli autio ja tyhjä, pimeys peitti syvyydet,
ja Jumalan henki liikkui vetten yllä. </TD>
</TR><TR ALIGN=LEFT VALIGN=TOP>
<TH>3</TH>
<TD>Dixitque Deus "Fiat lux" et facta est lux.</TD>
<TD>And God said, Let there be light: and there was light.</TD>
<TD>Jumala sanoi: "Tulkoon valo!" Ja valo tuli.</TD>
</TR></TABLE>
Notice that the ALIGN and VALIGN attributes can be essential for achieving good rendering. Browsers cannot know the nature of tables from their contents, so there are situations where the document author may need to control formatting issues like alignment.

Using a table to present a definition list

As mentioned in the discussion of list elements like DL, the typical rendering of "definition lists" is not very good. Moreover, there are just a few ways to affect the rendering.

Using a TABLE element for a definition list is perhaps not an intended use of that element but it is often useful, especially since the author can control things like alignment and use of borders. Consult the document Examples of various list elements in HTML for a very simple example of presenting a definition list as a table with default attribute settings. Usually you probably want the "definition terms" to be left-aligned, as in the following example:

Example table4.html:

<TABLE>
<CAPTION>The first three letters of the Greek alphabet</CAPTION>
<TR><TH ALIGN=LEFT>alpha</TH>
<TD> the first letter of the Greek alphabet </TD> </TR>
<TR><TH ALIGN=LEFT>beta</TH>
<TD> the second letter of the Greek alphabet </TD> </TR>
<TR><TH ALIGN=LEFT>gamma</TH>
<TD> the third letter of the Greek alphabet. </TD> </TR>
</TABLE>

Numerical tables

For many people, tables are essentially tables of numerical data. As the preceding examples show, tables have a lot of other uses as well.

For numerical tables, proper alignment is usually crucial for easily readable rendering. (It is in a sense a structural feature, since it relates to the comparability of items of a column.)

Integer values in a column should be right aligned. This is easy to achieve in principle. There are two alternatives:

Values containing a decimal point (or, in many languages, a decimal comma) should be aligned according to that separator, but unfortunately this is not possible in HTML 3.2. (There are suggested ways of expressing such requests, but currently there is little if any support for them.) One solution is to present such values so that there is the same number of digits to the right of the decimal point in every value in a column, and use ALIGN=RIGHT.

However, the rendering might be unsatisfactory if numbers are presented using a proportional font so that digits are of essentially different sizes. It is possible but tedious to overcome this by putting the data in each numerical cell within a TT element. (Notice that it is not legal for a TT element to contain a TABLE element!)

The following example contains first a hand-formatted table presented using the PRE element, then the same data using a TABLE element. In general, it takes more work and care to use a TABLE element but the result is often much better.

Example table5.html:

Measurement results:
<PRE>
time     temperature   pressure
12:00       26           12.8
12:15       22.5          9.8
12:30       11            1.65
12:45        3.3          0.03
13:00        0.05         0.002
</PRE>

<TABLE>
<CAPTION>Measurement results</CAPTION>
<TR><TH>time</TH><TH>temperature</TH><TH>pressure</TH></TR>
<TR ALIGN=RIGHT><TD>12:00 </TD><TD>26.00 </TD><TD>12.800 </TD></TR>
<TR ALIGN=RIGHT><TD>12:15 </TD><TD>22.50 </TD><TD> 9.810 </TD></TR>
<TR ALIGN=RIGHT><TD>12:30 </TD><TD>11.00 </TD><TD> 1.650 </TD></TR>
<TR ALIGN=RIGHT><TD>12:45 </TD><TD> 3.30 </TD><TD> 0.030 </TD></TR>
<TR ALIGN=RIGHT><TD>13:00 </TD><TD> 0.05 </TD><TD> 0.002 </TD></TR>
</TABLE>

Using tables to represent menus

Very often one needs to present a relatively large set of relatively small items. For instance, suppose that we have documents about various countries and we wish to provide a menu of country names, to be used as an index.

The index is implemented in HTML using normal links, e.g.
<A HREF="af.html">Afghanistan</A>
What we will discuss here is how to present the link names, or some other pieces of text, as a list, table, or some other structure.

If you only read HTML specifications, the obvious answer is to use the DIR or MENU construct. However, as mentioned and exemplified in the general discussion of lists, this is not practically feasible. Thus, if we prefer having the menu in multicolumn format, as we usually do, we must use other constructs.

Pseudo-table: preformatted text

One possibility is to format the menu by hand and enclose it into a PRE element. If the menu items are link texts, you should first format it as text only, then add the anchor (A) tags, since adding them obscures the layout. For clarity, therefore, the following example is presented without links (unlike the other alternatives):

Example menu1.html:

<PRE>
Afghanistan           Albania               Algeria
American Samoa        Andorra               Angola
Anguilla              Antarctica            Antigua and Barbuda
Arctic Ocean          Argentina             Armenia
</PRE>

Using just characters as separators

Another possibility, which should be the normal one, is to present the items simply as a text paragraph, using e.g. a blank or a blank and a comma as separator. Thus, you would plain text characters and not HTML markup to separate the items; not very structural, but it often works well. In this approach, the browser takes care of dividing the text into lines and the presentation is very compact:

Example menu2.html:

<BASE HREF="http://www.odci.gov/cia/publications/factbook/">
<P>
<A HREF="af.html">Afghanistan</A>,
<A HREF="al.html">Albania</A>,
<A HREF="ag.html">Algeria</A>,
<A HREF="aq.html">American Samoa</A>,
<A HREF="an.html">Andorra</A>,
<A HREF="ao.html">Angola</A>,
<A HREF="av.html">Anguilla</A>,
<A HREF="ay.html">Antarctica</A>,
<A HREF="ac.html">Antigua and Barbuda</A>,
<A HREF="xq.html">Arctic Ocean</A>,
<A HREF="ar.html">Argentina</A>,
<A HREF="am.html">Armenia</A>
</P>
Of course, it is possible to force line breaks by using a BR element (e.g. to make a change in the initial letter cause a new line in an example like above). If you think the items are not distinguishable enough in the rendering, consider prefixing each item with a special character like * (and using just spaces as separator) or using | and spaces around it as separators.

If we'd strongly prefer a presentation where items occupy the same amount of horizontal space, then one can either use the PRE method described above or take the effort of designing a suitable TABLE element. Example of the latter:

Example menu3.html:

<BASE HREF="http://www.odci.gov/cia/publications/factbook/">
<TABLE><TR>
<TD WIDTH=160><A HREF="af.html">Afghanistan</A></TD>
<TD WIDTH=160><A HREF="al.html">Albania</A></TD>
<TD WIDTH=160><A HREF="ag.html">Algeria</A></TD>
<TD WIDTH=160><A HREF="aq.html">American Samoa</A></TD>
</TR><TR>
<TD WIDTH=160><A HREF="an.html">Andorra</A></TD>
<TD WIDTH=160><A HREF="ao.html">Angola</A></TD>
<TD WIDTH=160><A HREF="av.html">Anguilla</A></TD>
<TD WIDTH=160><A HREF="ay.html">Antarctica</A></TD>
</TR><TR>
<TD WIDTH=160><A HREF="ac.html">Antigua and Barbuda</A></TD>
<TD WIDTH=160><A HREF="xq.html">Arctic Ocean</A></TD>
<TD WIDTH=160><A HREF="ar.html">Argentina</A></TD>
<TD WIDTH=160><A HREF="am.html">Armenia</A></TD>
</TR></TABLE>
Alternatively, you might wish to consider the effect of using a table with borders.

Notice that this solution is rather unclean. It involves a TABLE structure where the division into lines is (normally) made for layout purposes only, and adding new items usually requires complete restructuring of the table. You typically need to insert WIDTH attributes to ensure that table columns are of the same width, and the specification is inherently device-dependent since it must be given in pixels. In particular, the presentation might not be the desired one if the physical font size in pixels differs too much from what you think it should be. Moreover, the larger the sum of WIDTH attribute values for a row, the more probable it is that the presentation does not fit into a browser window without horizontal scrolling or, depending on the browser, without the browser deviating from the WIDTH suggestions, messing up the table.

Thus, this approach should be avoided in general, especially since it makes the document window width dependent. Hopefully future browsers will support the UL element in a more advanced way, automatically selecting a compact multicolumn presentation when applicable, or at least support the DIR element in the intended way.

A flexible pseudo-table

There is a trick which is a modification of the using just characters as separators between items but creates, in most browsing situations, the appearance of a table. The "table" even adapts to the browser window width so that the division of items to rows changes. Applied to our example, this works rather well. (I use this technique for the menu of element names in my Quick index to HTML 4.0 specification).

The idea is to pad the items with trailing no-break spaces so that each item has the same number of characters and use normal spaces (or newlines) between the items. Additionally, use some markup which causes monospace font to be used, such as TT. As a consequence, most browsers will treat the items as chunks of equal size and format the paragraph rather nicely. Drawbacks: monospace, or "teletype", font is not that nice, and implementing the trick is tedious (but you could use some authoring tool to generate the HTML document from some simpler format).

I call this a "trick" because it does not use logical markup and because there is no guarantee that it works. On the other hand, it is syntactically valid HTML, and in the rare cases where it does not work (since a browser "collapses" no-break spaces), the situation is no worse than when using just spaces as separators.

Table elements occupying several rows or columns

Sometimes we would like to make a table element occupy the space for two or more elements, horizontally or vertically or both. As an example, consider the following information (the declination of a Latin pronoun):
      neut. masc. fem.

nom.  id    is    ea
acc.  id    eum   eam
gen.  eius  eius  eius
dat.  ei    ei    ei
abl.  eo    eo    ea
Obviously this calls for using a table in HTML, and using the above-explained constructs you can write a simple table presentation for the data. However, if you would like to make it more explicit that there are identical entries in adjacent cells, you can use the ROWSPAN and COLSPAN attributes as follows:

Example span.html:

<TABLE BORDER=1 ALIGN=CENTER CELLPADDING=3>
<CAPTION>Declination of <I>is</I> in singular</CAPTION>
<TR><TH></TH><TH>neuter</TH><TH>masc.</TH><TH>fem.</TH></TR>
<TR><TH>nom.</TH><TD ROWSPAN=2 VALIGN=MIDDLE><I>id</I></TD>
 <TD><I>is</I></TD><TD><I>ea</I></TD></TR>
<TR><TH>acc.</TH><TD><I>eum</I></TD><TD><I>eam</I></TD></TR>
<TR><TH>gen.</TH><TD COLSPAN=3 ALIGN=CENTER><I>eius</I></TD></TR>
<TR><TH>dat.</TH><TD COLSPAN=3 ALIGN=CENTER><I>ei</I></TD></TR>
<TR><TH>abl.</TH><TD COLSPAN=2 ALIGN=CENTER><I>eo</I></TD>
 <TD><I>ea</I></TD></TR>
</TABLE>
For example, the first cell is specified to have ROWSPAN=2, which effectively means that two adjacent cells in the same column are combined into one cell. Notice that when writing the HTML code for the next row (the second TR element) we simply leave out a cell element corresponding to the location which has already been taken into use.

Nested tables

Tables can be nested, because a TD element (and a TH element) may contain a block element and therefore a table element in particular.

Nested tables easily become confusing. Moreover, there are browsers which cannot handle nested tables in general or which get confused with complicated nested tables. Of course, nested tables can be the natural way of expressing information, when it is logically an array of something which may in turn be an array.

Basically you just need to be very careful in writing HTML code for nested tables. No new elements or other features are needed, just a combination of those which have already been described. But due to deep nesting one easily makes mistakes, and the results can be really messy, and locating the error may take time.

The simplest case is probably a table with a single row consisting of two elements, each of which is a table. This might be used for presenting two similar tables in parallel for comparison. To proceed with our grammatical example, here is a table containing two tables, one for declination in singular and one for declination in plural:

Example nt.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<TITLE>tbl</TITLE>
<TABLE ALIGN=CENTER>
<CAPTION>Declination of <I>is</I></CAPTION>
<TR><TD>
<TABLE BORDER=1 ALIGN=CENTER CELLPADDING=3>
<CAPTION>Singular</CAPTION>
<TR><TH></TH><TH>neuter</TH><TH>masc.</TH><TH>fem.</TH></TR>
<TR><TH>nom.</TH><TD ROWSPAN=2 VALIGN=MIDDLE><I>id</I></TD>
 <TD><I>is</I></TD><TD><I>ea</I></TD></TR>
<TR><TH>acc.</TH><TD><I>eum</I></TD><TD><I>eam</I></TD></TR>
<TR><TH>gen.</TH><TD COLSPAN=3 ALIGN=CENTER><I>eius</I></TD></TR>
<TR><TH>dat.</TH><TD COLSPAN=3 ALIGN=CENTER><I>ei</I></TD></TR>
<TR><TH>abl.</TH><TD COLSPAN=2 ALIGN=CENTER><I>eo</I></TD>
 <TD><I>ea</I></TD></TR>
</TABLE>
</TD>
<TD>
<TABLE BORDER=1 ALIGN=CENTER CELLPADDING=3>
<CAPTION>Plural</CAPTION>
<TR><TH></TH><TH>neuter</TH><TH>masc.</TH><TH>fem.</TH></TR>
<TR><TH>nom.</TH><TD ROWSPAN=2 VALIGN=MIDDLE><I>ea</I></TD>
 <TD><I>ii (ei)</I></TD><TD><I>eae</I></TD></TR>
<TR><TH>acc.</TH><TD><I>eos</I></TD><TD><I>eas</I></TD></TR>
<TR><TH>gen.</TH><TD COLSPAN=2 ALIGN=CENTER><I>eorum</I></TD>
 <TD><I>earum</I></TD></TR>
<TR><TH>dat.</TH><TD COLSPAN=3 ROWSPAN=3 ALIGN=CENTER VALIGN=MIDDLE>
 <I>iis (eis)</I></TD></TR>
<TR><TH>abl.</TH></TR>
</TABLE>
</TD>
</TABLE>

Notice the explicit use of end tags like </TD>. The same code with omissible tags omitted is equivalent according to HTML 3.2 specification, but Netscape has a bug which can make it present a nested table incorrectly in the absence of end tags.

Alignment of cells

Alignment of cells, i.e. the positioning of the contents of a table cell (within the space reserved for the cell by a browser), is important in tables containing numerical data. You may wish to control it in other contexts as well.

The default alignment is the following:

There is no way to set different defaults for an entire table. (Although the TABLE element accepts an ALIGN attribute, it affects the positioning of the entire table!)

However, you can use the ALIGN and VALIGN attributes in TH and TD elements to set the alignments for an individual cell, and you can use the same attribute in a TR element to set the alignment defaults for the cells within that element ( i.e. within one row); naturally, such defaults can be overridden in individual elements.

The possible values of ALIGN (in TH, TD and TR elements) are LEFT, RIGHT, and CENTER, for aligning the contents of a cell horizontally with respect to the left, center or right within the space for the cell. Notice that when aligning to the left or right, there can still be some space between the content of a cell and the left or right lower border of the cell, depending on the setting of the CELLPADDING attribute of the enclosing TABLE element.

The possible values of VALIGN (in TH, TD and TR elements) are TOP, MIDDLE, and BOTTOM, for aligning the contents of a cell vertically with respect to the top, center or bottom of the space for the cell. As stated above, the default is VALIGN=MIDDLE. Notice that when VALIGN=TOP or VALIGN=BOTTOM is used, there can still be some space between the content of a cell and the upper or lower border of the cell, depending on the setting of the CELLPADDING attribute of the enclosing TABLE element.

Fonts in table elements

People often ask how to designate font face, size and color for data within tables.

The short answer is: Don't. When necessary, use logical markup for text elements within tables as well as elsewhere. (Previous discussion contained a simple example of this.)

Assuming that you really need to designate font face, size and color (or just insist on doing so), the laborious way of doing it elementwise is the only portable way. Here portable means that you can, with some confidence, expect the HTML code to work on most browsers (assuming that they have table support at all, of course). This is not just a standards issue. In particular, in Netscape the BASEFONT element does not affect text in tables (it is disputable whether it should, according to the standard).

To summarize the situation, as regards to portable solutions in the above-mentioned sense:

font face
Cannot be set in HTML 3.2 at all. You can only use a few markup elements to suggest that a font of a specific kind (e.g. italics, monospaced, bold) be used. These cannot be set globally, i.e. if you want them to apply to all elements of a table, they must appear separately in each TH or TD element. (The FACE attribute of the FONT element is not allowed in HTML 3.2, though mentioned as a feature which is supported by some browsers. It is valid, though deprecated as the entire FONT element is, in HTML 4.0. And it is "local", text level markup, so it really needs to be put into each table cell separately.)
font size
Locally (e.g. within a table cell) you can use SMALL, BIG, or FONT SIZE=... You can set the global (default) font size with BASEFONT but this usually does not affect table cell contents, as explained above.
font color
Locally (e.g. within a table cell) you can use FONT COLOR=... You can set the default text color globally - in the absolute sense, for the entire document - with BODY TEXT=... But you cannot set the default color for a table to be different from that of the entire document.

Style sheets provide tools for affecting the rendering in a rather detailed manner, but support for them in browsers is still under development.


Date of last update: 2010-12-16.
This page belongs to the free information site IT and communication, section Web authoring and surfing, by Jukka "Yucca" Korpela.