14

14Tables and Footnotes

14.2

The standard table

The tables within the template website are based around the properties discussed in the previous section; except this time the basic styles are all done in the style.css file.

The tables are also much more subtle than that shown in the previous examples.

Where I’ve used tables to represent a grid of information, I’ve generally used borders very sparingly (and colours not at all), here is an example:

Item Function
01 Functional description 1
02 Functional description 2
03 Functional description 3
Table 14.1   A simple table style

In practice, I probably wouldn’t even go this far, the following is more typical of my tables:

Item Function
01 Functional description 1
02 Functional description 2
03 Functional description 3
Table 14.2   The standard table

The eye tends to fill in the rows and columns automatically. I don’t use vertical borders at all.

To highlight the table and distinguish it from the body text, the table is narrower than the width of the body text (it is 84% of the body text width).

The table also uses a san-serif font (Concourse) as opposed to the serif (Equity) font of the body text. The headings are in light-grey all-caps version and are smaller than the body text.

So how have I done it? Let’s have a look at the basic HTML for the very simple table above (Table 14.2):

standard table html
<table class="table-clean" id="js--t14-02">
    <tr>                                                            <!-- Header row -->
        <th class="leading"></th>
        <th class="table-cent" style="width: 25%">Item</th>
        <th class="table-left" style="width: 75%">Function</th>
    </tr>
    <tr class="no-border">                                          <!-- Data row -->
        <td class="leading" style="height: 3em"></td>
        <td class="table-cent">01</td>
        <td class="table-left">Functional description 1</td>
    </tr>
    <tr class="no-border">                                          <!-- Data row -->
        <td class="leading" style="height: 3em"></td>
        <td class="table-cent">02</td>
        <td class="table-left">Functional description 2</td>
    </tr>
    <tr>	                                                    <!-- Data row -->
        <td class="leading" style="height: 3em"></td>
        <td class="table-cent">03</td>
        <td class="table-left">Functional description 3</td>
    </tr>
    <tr class="no-border">                                          <!-- Caption row -->
        <td class="leading"></td>
        <td colspan="2" class="table-caption">Table 14.2 Standard table</td>
    </tr>
</table>
Code 14.2   Standard table HTML

Now, with the exception of a few classes, this is pretty much the same as the example table of § 14.1. The only peculiarity is that there is an extra column, it’s the first cell in each row (even the header row) and it always has the class leading (that is leading to rhyme with bedding not speeding, see § 3.2.2). I use this as a placeholder to set the height of the row (I explain further below).

Ok, first things first, I declare the table and give it the class table-clean, I also give the table an ID in the form js--tcc-nn (where t just means table, cc is the chapter number and nn is the consecutive number of the table within the chapter); the table has an ID because it has a numbered caption and is an object that can be scrolled to by clicking a link (this is similar to figures and code fragments; section 17 gives a full description of how these IDs are specified and how the slow scrolling works).

Let’s look at the CSS for table-clean, there is a fair amount of code here, but it straight forward styling stuff — it just has to cover each type of cell (<th> and <td>):

standard table css
.table-clean {
    width: 84%;
    margin: 0 auto;
    border-collapse: collapse;
    margin-bottom: 1rem;
    font-family: "conc-t3-r";
    font-feature-settings: "ss02";
    font-size: 0.7rem;
}
.table-clean th {
    font-family: "conc-t2-r";
    font-feature-settings: "ss02";
    text-transform: uppercase;
    letter-spacing: 0.086em;
    color: #7F7F7F;
    padding: 0.8rem 0.2rem 0.25rem 0.2rem;  /* top padding to separate from prev text */
    border-bottom: 1px solid #cccccc;
}
.table-clean td {
    padding: 0.25rem 0.2rem;
    line-height: 120%;
    border-bottom: 1px solid #cccccc;
}

.table-clean th:first-child {               /* first-child is leading */
    padding: 0;                             /* remove margins and padding */
    margin: 0;
}
.table-clean td:first-child {              /* first-child is leading */
    padding: 0;                            /* remove margins and padding */
    margin: 0;
}

.table-clean p {                            /* if paragraphs are used add more space */
    margin-top: 0.3rem;
    margin-bottom: 0.8rem;
}
.table-clean p:last-child {
    margin-bottom: 0.3rem;
}

.table-clean em {
    font-family: "conc-t3-b";
    font-feature-settings: "ss02";
    font-style:normal;
}
Code 14.3   Standard table CSS

The whole table has the class table-clean and this defines the basic properties for the table. The first bit sets the table to a width of 84%, this is 84% of the parent element which in this case is the central area of the web page (where the body text lives), if looking at the web page in a full width browser the central area is 748 px wide and the table will be 84% of this or 628 px:

.table-clean {
    width: 84%;
    margin: 0 auto;

The margin removes any top and bottom margins and centres the table in the web page (by setting the left and right margins to auto).

Next I make any borders applied to cells within the table join up with each other (see § 14.1.2):

    border-collapse: collapse;

I also add a bottom margin to leave a space after the table and before any following paragraph:

    margin-bottom: 1rem;

This spacing makes the distance from the baseline of the text in the table caption to the baseline of a following paragraph correct (I measured it — with a ruler — still an engineer).

The rest of it sets the text properties (this is the same stuff we do everywhere):

    font-family: "conc-t3-r";
    font-feature-settings: "ss02";
    font-size: 0.7rem;

The text is Concourse t3 (san-serif) font with the British stylistic set (ss02) and a smaller font size of 0.7 rem (all the usual stuff).

Now I set the styles for the different cell types (heading and data), these are part of the <table> element and thus use the descendant selector. Heading first:

.table-clean th {
    font-family: "conc-t2-r";
    font-feature-settings: "ss02";
    text-transform: uppercase;
    letter-spacing: 0.086em;
    color: #7F7F7F;
    padding: 0.8rem 0.2rem 0.25rem 0.2rem;
    border-bottom: 1px solid #cccccc;
}

To start with I’ve selected only the <th> elements that are associated with the table-clean class (rather than every <th> element which is what would have been selected if I hadn’t added .table-clean beforehand):

.table-clean th {

The code then is just being applied to heading elements (<th>) within a table that has been given the table-clean class (this is important because, as you will see, there are other types of table and I don’t want to cross contaminate them).

The heading uses a slightly lighter font (Concourse t2 rather than t3) and again applies the British stylistic set:

    font-family: "conc-t2-r";
    font-feature-settings: "ss02";

The next two lines make the heading text all-caps (text-transform: uppercase) and increase the spacing between the letters:

    text-transform: uppercase;
    letter-spacing: 0.086em;

The letter spacing is increased to make the text look better (see Mr Butterick’s website for an explanation).

I also change the colour of the heading text to a lighter grey, I do this to dilute the effect of the all-caps, If I left the colour the standard dark grey of the body text the headings are a too noticeable (a bit shouty).

    color: #7F7F7F;
    padding: 0.8rem 0.2rem 0.25rem 0.2rem;

I add some padding to the heading cells: 0.2 rem to the left and right to stop text in adjacent cells butting up to each other. I add 0.8 rem above the heading to give the correct spacing from any previous paragraph and finally I add some bottom padding to leave a gap between the text and the bottom border.

The bottom border is a solid 1 pixel high line in a light grey colour:

    border-bottom: 1px solid #cccccc;

The border is applied by default; a heading cell will always have a bottom border unless action is taken to remove it (see below, § 14.2.6).

The specific setting for a data cell (<td>) is done in much the same way as the settings for a heading cell:

.table-clean td {
    padding: 0.25rem 0.2rem;
    line-height: 120%;
    border-bottom: 1px solid #cccccc;
}

Again, I’ve selected only the <td> elements that are associated with the table-clean class and for the same reason:

.table-clean td {

The data cells use the font set in the table-clean class and so there are no font declaration applied here (they’re not needed).

I’ve added some padding to the cells: 0.25 rem above and below the text and 0.2 rem to either side, again this is to stop any text brushing up against the edges of the cell.

The line height has been set to 120% (body text is set to 135%), I judged this setting by eye, 120% is the smallest line spacing that should be used see § 3.2.3, and it looks right in the tables, I want the table text to be denser than body text.

Finally, there is a bottom border:

    border-bottom: 1px solid #cccccc;

This is identical to the heading cell border and is again applied by default to every cell (unless steps are taken to prevent this see § 14.2.6).

14.2.1

The leading cell

Before I finish the table-clean class description, I need to explain the peculiar cell I’ve added to the start of each row in the table. It looks like this for a row of data cells (<td>):

        <td class="leading" style="height: 3em"></td>

And for the heading row:

        <th class="leading"></th>

The only purpose of this cell is to set the height of the row that contains it.

The cell has been given the class leading. The CSS for which is:

.leading { width: 0; }

There is not much too it, it has a width of zero pixels (i.e. it has no visible width).

There is also no text content to the cell, there is no text between the <td> and the </td>; this is important leading cell must not contain any text. If text is placed in a leading cell it will appear on the screen and give the cell a visible width.

Never put text in a leading cell

The idea behind the leading cell is to give a common point in each row within which the defining height for the row can be set.

By default, the height of a row of cells is set by the cell that has the highest content (see § 14.1.4). The purpose of the leading cell it to make this the highest cell in the row and this is done simply by specifying a height for the leading cell using the style attribute in the HTML — you can see it below (in bold and highlighted in green):

        <td class="leading" style="height: 3em"></td>

In this case, I’ve set the height of the leading cell to be 3 em, giving the row artificial height (the row is taller than it needs to be to accommodate the cell contents in that row).

Why ems and not rems? Well, I’ve used ems to make the spacing proportional to the text within the table (I know that this in turn is defined in rems), if the table font size is change (or overridden with a style attribute), the spacing will change with it.

So here are the rules for the leading cell:

  1. Each row including the heading row should have a leading cell

  2. The leading cell should be the first cell in each row

  3. The leading cell sets the height of the row by using the style attribute in the HTML

You might also wonder why I use the leading cell to set the height in the HTML. The reason is that each table is unique, some tables may have long texts within them and some short, the height of a row is thus entirely dependent on what the table contains. If I were to set the height of the leading cell in the CSS file, it would apply to every table on the website.

Hence, this is one of those situations where it is better to use the style attribute directly in the HTML for each instance of a standard table.

  • If no height is applied to a leading cell, the row will adopt the height of the cell with the highest content; the leading cell will do nothing (this tends to be the case with the heading row). The leading cell must always be there though, even if it is not supplying a height.

14.2.2

Margin and padding arrangements for the leading cell

Back to the table-clean CSS; the table-clean class applies margins and padding to <th> and <td> elements to keep them clear of the cell borders.

These settings are also applied to the leading cell and this will effectively give some dimensions to the leading cell (i.e. it will have the width defined in the margin and padding settings) and we don’t want this, the leading cell should specify the height of the row, but should have zero width.

It is necessary to remove the margin and padding settings for the leading cell; and since the leading cell is always the first cell in a row, we can use the first-child pseudo class to remove the margins:

.table-clean th:first-child {               /* first-child is leading */
    padding: 0;                             /* remove margins and padding */
    margin: 0;
}
.table-clean td:first-child {              /* first-child is leading */
    padding: 0;                            /* remove margins and padding */
    margin: 0;
}

There are two of these, one for the <th> leading cell (used in the heading row) and one for the <td> leading cell (used on all rows apart from the heading row). The actions are the same for each, it just sets the margin and padding to zero for the first cell in each row:

    padding: 0;                            /* remove margins and padding */
    margin: 0;

14.2.3

Paragraph styling within a cell

Tables generally hold data in the form of brief entries: numbers, names, brief descriptions &c. and the table-clean class is setup for just such usage and most entries are just made between the <td> and </td> tags without any qualification (just put the text or numbers that are to appear in the cell in between the tags and it just works).

However, there are situations where a cell needs more information and this might consist of more than one paragraph (this is the flexibility of tables, they can be used for anything); where multiple paragraphs are used in a cell, paragraph spacing is required.

Let’s suppose we want to add to the Functional description 1 text in the above example and make it read:

Functional description 1
The basic operator controls

If in the HTML. I add a <br> element and the remaining text to the cell as follows:

<td class="table-left">Functional description 1<br>The basic operator controls</td>

It gives the following result:

Item Function
01 Functional description 1
The basic operator controls
02 Functional description 2
03 Functional description 3
Table 14.2   The standard table

It puts the text onto two lines, but without any additional paragraph spacing. To get around this I’ve defined another descendant selector for the paragraph element <p> within the table-clean class:

.table-clean p {
    margin-top: 0.3rem;
    margin-bottom: 0.8rem;
}
.table-clean p:last-child {
    margin-bottom: 0.3rem;
}

The first descendant selector: table-clean p, just applies paragraph spacing above and below each <p>...</p> entry in a cell in the table.

The second entry table-clean p:last-child removes some of the additional space below the last paragraph, this is because the table-clean class already has margins set to give some spacing above the bottom edge of the cell, the last paragraph doesn’t need as much space below it.

If I change the table cell to use paragraphs instead of the <br>, it looks like this:

<td class="table-left"><p>Functional description 1</p>
<p>The basic operator controls</p></td>

And the table now looks like this:

Item Function
01

Functional description 1

The basic operator controls

02 Functional description 2
03 Functional description 3
Table 14.2   The standard table

The separate paragraphs are now properly spaced.

The general rules for this are:

  • For single sentence entries in a cell, just enter the text directly after the <td> or <th> tag

  • Where multiple paragraphs are required, enter the text after the <td> or <th> tag but this time surround the text for each paragraph with a <p>...</p> element

The em style within the standard table is again set to a Concourse (san-serif), with normal body text the em style is a serif font, but within the table we want it to be a san-serif.

14.2.4

Setting the width of each column

I used the leading cell as the first entry in a row to set the height of a row; the table has by default a heading row at the top and I use the cells within this to set the width of the columns.

It can be seen in the HTML (in bold with a red underline):

    <tr>
        <th class="leading"></th>
        <th class="table-cent" style="width: 25%">Item</th>
        <th class="table-left" style="width: 75%">Function</th>
    </tr>

Ignoring the leading cell (the first cell of the row), each cell in the heading row has a style attribute that sets the width of the column. In this case there are two; the Item column is set to 25% and the Function column to 75%.

  • These percentages are percentages of the table width, which in itself, is 84% of the central column area. I.e. in this example, the 25% and 75% are 25% and 75% is of the 84% table width.

If the table had three proper columns (not including the leading column), there would be three percentages.

The percentages for each column must always add up to 100%.

If the percentages do not add up to 100%, the columns distribution will look odd, the browser will decide that one column needs to be wider and will adjust the table accordingly — it’s fair to say that it usually picks the wrong column.

The style attribute is used in exactly the same way as that described in the example of § 14.1.3.

14.2.5

Aligning the text

Text in a cell can be horizontally aligned as follows:

  • Left justified

  • Centred

  • Right justified

By default <th> cells will be centred and <td> cells left justified.

To change the alignment of a particular cell just apply one of the following classes to the cell:

  • table-left

  • table-cent

  • table-right

The do exactly what you think. Looking at the heading row of the HTML:

    <tr>
        <th class="leading"></th>
        <th class="table-cent" style="width: 25%">Item</th>
        <th class="table-left" style="width: 75%">Function</th>

The Item cell has class table-cent to centre the text and the Function cell has table-left to left justify it. These classes work exactly as you would expect:

.table-left  {text-align: left;}
.table-cent  {text-align: center;}
.table-right {text-align: right;}

It uses the text-align property to left, centre or right justify the text.

I don’t have any code to vertically align the text, the text will by default be vertically centred within a cell (this is the default action of the table), and generally this is exactly what I want a cell to do.

If you do want to vertically align text within in a cell, do exactly what I did in § 14.1.5

Use the style attribute with vertical-align in the HTML for that cell. The values for this property are: top, middle and bottom. For example to make the number 01 align vertically with the top of its cell change the line to:

        <td class="table-cent" style="vertical-align: top" >01</td>

It would be perfectly possible to define CSS classes for this (just like the horizontal alignment), I should have I know, I just haven’t — I pretty much always want the text to be centred vertically and to be honest it didn’t occur to me that something was missing until I started writing it up. Add them if you like — I will be doing so at the next revision of the website, they will be called table-top, table-mid and table-bot.

14.2.6

Table borders

By default the table-clean (standard) type of table always has a light grey border at the bottom of each row. The previous table would look like this with default settings:

Item Function
01

Functional description 1

The basic operator controls

02 Functional description 2
03 Functional description 3
Table 14.2   The standard table

Every row gets a bottom border, even the last one; this is because the table-clean defines a bottom border for both the <th> and <td> descendant selectors:

    border-bottom: 1px solid #cccccc;

If a border is not required for a particular row, that row must have the class no-border applied to it:

    <tr class="no-border">
        <td class="leading" style="height: 3em"></td>
        <td class="table-cent">01</td>
        <td class="table-left">Functional description 1</td>
    </tr>

Here the <tr> element has been given the class no-border and the result is that there is no visible border.

The CSS behind this is straight forward:

tr.no-border td,
tr.no-border th {                           /* no-bottom border */
    border-bottom: 1px solid transparent;
}

It sets the border for both <th>and <td> elements to solid white with a height of 1 pixel.

It doesn’t actually turn the border off; it makes it transparent so it doesn’t show up. The reason I do this instead of just turning the border off is that it keeps everything aligned properly, if I turned the border off, a row without a border would be 1 pixel shorter than the one with a border (the border takes up one pixel).

So the rule is:

  • If you don’t want a border use <tr class="no-border">

  • If you do want a border use <tr>

14.2.7

Table captions

This is the last bit.

The last row of a table is the caption row:

    <tr class="no-border">                  <!-- caption row -->
        <td class="leading"></td>
        <td colspan="2" class="table-caption">Table 14.2 &emsp; Standard table</td>
    </tr>

This starts off as a normal row with the no-border class (there is no border after the caption row):

    <tr class="no-border">

The first cell in the row is a basic leading cell (this time it does not specify any height):

        <td class="leading"></td>

All standard stuff so far. Next comes the only odd bit, the caption itself, this merges the cells in the row using a colspan attribute (see § 14.1.6)

        <td colspan="2" class="table-caption">Table 14.2 Standard table</td>

The colspan should be set to span all the visible columns in the table; it must not include the leading column. In this case there are two rows (Item and Function) and so the colspan attribute is set to 2, if there were three columns it would be set to 3 &c.

This is followed by the table-caption class:

.table-caption {
    font-family: "conc-t3-r";
    font-feature-settings: "ss02";
    font-size: 0.6rem;
    text-align: left;
}

This just defines the text properties for the caption text: Concourse with British styling and a font-size of 0.6 rem (the caption is quite small). It also ensures that the text is left justified.

Table captions are not compulsory, but I tend to use them. Where they are used, the table number in the caption should match the table number given in the ID (right at the start of this section). In this example the table has ID js‑‑t14‑02:

<table class="table-clean" id="js--t14-02">

I.e. table 14.2.

The text in the caption cell reflects this, it has:

        <td colspan="2" class="table-caption">Table 14.2 Standard table</td>

Table 14.2, both the caption and the ID refer to the same table.

Tables that have numbered captions are often referenced in body text and this ID allows a link to be instated that will navigate directly to the table in question (see § 17).



End flourish image