SITERAW

HTML tables

Now that we built our website (see the last chapters of the previous part), what could possibly be left to cover in this tutorial?

This might come to a surprise to some of you, but we still aren't done with HTML and CSS.

There are many more so-called "advanced", and I use this term loosely, features that we have yet to discover.

Amongst them are tables.

You probably know what a table is, defined as a set of facts or figures systematically displayed, usually in rows and columns.

We'll start by introducing the concept of tables in HTML, particularly detailing their use, before building our own simple tables, then moving on to a slightly more complex variety, and finally concluding this chapter with a special case: when you need to merge either rows or columns.

We'll see a bit of CSS too, but most of the properties we'll use have already been covered in previous chapters.

Tables are easy, tables are fun, and my use of the "advanced" adjective was more out of terminological laziness than anything.

There is nothing complicated about this HTML feature, so let's begin without further ado.

An introduction to tables

Tables are a new way of organizing content in HTML.

Imagine you want to make a list of every computer language you know of.

We already know how to do that! All we need are the <ul> and <li> tags!

That's true.

We saw in the Organize your text chapter how to create bullet lists.

But imagine that in addition to showing the names of every computing language you know of, you also want to display their current version, the year in which they were invented and their purpose.

We can try the following code.

<ul>
    <li>HTML (5, 1991, markup)</li>
    <li>CSS (3, 1996, presentation)</li>
    <li>Javascript (1, 1995, scripting)</li>
</ul>

This would give us the following result.

  • HTML (5, 1991, markup)
  • CSS (3, 1996, presentation)
  • Javascript (1, 1995, scripting)

It gets the job done, but it's not very readable.

The problem with this example is that there is more than one value per list item.

We would need something that makes comparing each individual value easier and more ergonomic.

Something with both rows and columns.

Something like... tables.

Here is an example of what you can obtain with tables in HTML and CSS.

LanguageVersionFoundedPurpose
HTML51991Markup
CSS31996Presentation
Javascript11995Scripting

Much easier on the eyes.

This is just a basic table with minimal CSS.

If you want to see a more elaborate example of what is possible with tables, have a look at the figure below.

Tables in HTML and CSS
Tables in HTML and CSS

Pretty cool, right?

Keep reading this chapter to see how you can achieve similar results, and much more.

But before anything we should start with basics.

Simple HTML tables

While tables are great for organizing information in a clear and readable way, their implementation on a web page is a bit more complex than what we are used to.

The reason is that to display a table, you need to write a specific sequence of multiple nested HTML tags in the correct order.

When you think about it, even the most basic tables are composed of at least four elements.

  • a table container
  • rows
  • columns
  • table cells

If you want to simplify things even further, you don't even need to define rows, columns and table cells, as knowing the numerical value of at least two of these variables allows you to determine the third without it being specified.

We can safely remove one of those three variables.

The creators of HTML must have thought that having a column tag would be redundant so... bye columns.

We are now left we three components: the container, the rows and the table cells.

And it just so happens that the HTML language has a specific tag for each of these three elements.

  • <table> for the table
  • <tr> for the rows (stands for table row)
  • <td> for the cells (stands for table data cell)

Let's see what all these tags do, and how they are used in conjunction with one another.

The container element

The first HTML element you need to know is the <table> tag.

This is the table container which, by definition, will contain everything else that we will cover in this chapter.

It's a block tag, so it has to be placed outside of paragraphs.

<p>A paragraph before the table.</p>

<table>
    <!-- The table itself -->
</table>

<p>A paragraph after the table.</p>

Obviously, this code alone won't do much: it simply delineates the beginning and end of a table.

To add content to our table we will need to use the two other tags we just discovered: <tr> and <td>.

Table rows and data cells

As I said before, creating tables in HTML is simply a matter of placing these tags in the correct sequence.

First we create our table rows with the <tr> element, then we add as many cells as we want inside each row with <td>.

Tables, rows and cells
Tables, rows and cells

For example, if I want a table with two rows and three columns per line, I can write the following.

<table>
    <tr>
        <td>HTML</td>
        <td>Markup</td>
        <td>1991</td>
    </tr>

    <tr>
        <td>CSS</td>
        <td>Presentation</td>
        <td>1996</td>
    </tr>

    <tr>
        <td>Javascript</td>
        <td>Scripting</td>
        <td>1995</td>
    </tr>
<table>

Remember the order: table > row > cell.

You can obviously add as many rows and cells per line as you want.

A table illustration
A table illustration
That sucks! It doesn't even look like a table!

That's because we haven't added any CSS yet.

Styling tables with CSS

A plain HTML table isn't very aesthetically pleasing to say the least, so let's move on to the CSS for now.

The first step would be to add a border to each cell like I did in my illustrations.

We already know the property used to add borders to an element, all that's left is to apply it to the <td> tag.

And for good measure, let's also add a padding and center the text horizontally.

td
{
    border: 1px solid #aaa;
    padding: 5px;
    text-align: center;
}

And the result.

Adding borders to our cells
Adding borders to our cells

You may have noticed that the borders which we have now made visible are separated via a margin by default.

What if we want only a single border between each cell and no margin?

Fortunately, there is a CSS property that applies only to tables and that does exactly that.

Border collapsing

The border-collapse property is used to indicate whether a table's borders should be separated or collapsed.

It can take two values:

  • separate : adjacent cells have distinct borders (default).
  • collapse : adjacent cells have shared borders.

Since our goal is to have a single shared border, let's try to second value.

Don't forget that it applies to the table element.

table { border-collapse: collapse; }

td
{
    border: 1px solid #aaa;
    padding: 5px;
    text-align: center;
}

You can see the result below.

A table with basic CSS
A table with basic CSS

That looks much more like a table.

You can of course use any other CSS property you know of to stylize either the table, the rows or the cells as much as you wish.

CSS table border styles
CSS table border styles

Advanced HTML tables

Up until now we've learned how to create tables as well as add rows and data cells.

That's cool, but still pretty limited.

Time to discover some more advanced features of HTML.

Header cells

Tables are a great way to display data in a readable and accessible fashion.

But to be able to make sense and use of the data displayed, you need to understand what each column represents.

In addition to the <td> element (table data cell), HTML also provides us with a <th> tag that stands for table header cell.

The latter is used just like the former, except for the fact that it contains header content.

Header content will generally be a description of the column containing the header cell.

Expanding upon our demonstration table.

<table>
    <tr>
        <th>Name</th>
        <th>Purpose</th>
        <th>Founded</th>
    </tr>

    <tr><td>HTML</td><td>Markup</td><td>1991</td></tr>

    <tr><td>CSS</td><td>Presentation</td><td>1996</td></tr>

    <tr><td>Javascript</td><td>Scripting</td><td>1995</td></tr>
<table>

You can see the result in the figure below.

A table with header cells
A table with header cells

By default the browser will display the header text in bold, but you can change it in CSS.

Remember that header cells <th> replace regular data cells <td>. For some reason, a lot of beginners get confused and replace the entire table row <tr> with <th>... header cells, not header rows.

The scope attribute

Not very often used but good to know nonetheless, <th> possesses an element specific attribute: scope.

The scope attribute determines the cells that the header relates to.

It can take the following two values.

  • col : the header relates to the column it belongs to (default).
  • row : the header relates to the row it belongs to.

The only reason why you'd want a header relating to one of your rows is if you are using a double entry table or double entry matrix.

The most famous example of a double entry table.

A multiplication table
A multiplication table

And here is the code to produce the above result.

<table>
    <tr>
        <th></th>
        <th scope="col">1</th>
        <th scope="col">2</th>
        <th scope="col">3</th>
    </tr>

    <tr><th scope="row">1</th><td>1</td><td>2</td><td>3</td></tr>
    <tr><th scope="row">2</th><td>2</td><td>4</td><td>6</td></tr>
    <tr><th scope="row">3</th><td>3</td><td>6</td><td>9</td></tr>
</table>

You can use both header cells <th> and regular data cells <td> on the same row to produce a table with vertical headings.

This isn't often used outside of double entry tables (what we just saw).

A table caption

We learned about header cells which describe the content of each column they belong to.

It makes the table more readable.

But we're still lacking something to explain the purpose of the table itself, not just that of the columns or rows.

Tables often have titles used to do just that: in our example, our title would be something like "The languages of websites".

The HTML element we need is called <caption> and it contains the title of your table.

Here is how it's used.

<table>
    <caption>Web languages</caption>

    <tr>
        <th>Name</th>
        <th>Purpose</th>
        <th>Founded</th>
    </tr>

    <tr><td>HTML</td><td>Markup</td><td>1991</td></tr>

    <tr><td>CSS</td><td>Presentation</td><td>1996</td></tr>

    <tr><td>Javascript</td><td>Scripting</td><td>1995</td></tr>
<table>

You can see the result below.

A table with a caption
A table with a caption

We can apply CSS styles to the table caption just like any other HTML element.

Styling the caption

You can change the caption position using the CSS caption-side property which applies to the caption element and can take the the following two values.

  • top : the caption will be placed above the table (default).
  • bottom : the caption will be placed below the table.

Let's add some CSS to our caption to make it stand out.

caption
{
    caption-side: bottom;
    font-weight: bold;
    letter-spacing: 1px;
    font-style: italic;
}

And the result.

A caption with CSS
A caption with CSS

The two CSS properties border-collapse and caption-side are noteworthy as they are specific to tables, so you won't run into them very often.

They are also the only two new CSS properties we will cover in this chapter.

Structured tables

We could leave our table like this.

But if you want your tables to be even more semantically structured, you may want to divide them into several distinct fields.

HTML has three elements, one for each table part.

  • <thead> : for the heading of the table
  • <tbody> : for the body of the table
  • <tfoot> : for the footer of the table

These new elements wrap around the table rows <tr>.

What's the point of using another tag for the heading? Don't we already have <th> to do that?

The <th> element indicates that the table cell contains column header information, thus it replaces the "regular" data cell <td> element.

It can be used either independently or in conjunction with <thead>.

The <thead> element on the other hand specifies that the entire row, or set of rows, contained within are to be treated as headers.

The best way to understand the purpose of these three tags is to add them to our example, dividing our table into three distinct parts.

<table>
    <caption>Web languages</caption>

    <thead>
        <tr><th>Name</th><th>Purpose</th><th>Founded</th></tr>
    </thead>

    <tfoot>
        <tr><th>Name</th><th>Purpose</th><th>Founded</th></tr>
    </tfoot>

    <tbody>
        <tr><td>HTML</td><td>Markup</td><td>1991</td></tr>

        <tr><td>CSS</td><td>Presentation</td><td>1996</td></tr>

        <tr><td>Javascript</td><td>Scripting</td><td>1995</td></tr>
    </tbody>
<table>

The order of elements is now table > thead/tbody/tfoot > tr > th/td.

I added a bit of CSS to the result to delineate the three different fields of our table.

A semantically structured table
A semantically structured table

Something you might have noticed is that the table footer <tfoot> is above the <tbody> element in our HTML code.

This is just a code convention, probably for practical accessibility reasons since the content within <tbody> usually takes up the most space.

Why are the <thead> and <tfoot> lines identical?

In very long tables, where you might want to visitor to avoid having to scroll all the way back to the top to see what each column is about, it's common to simply duplicate the header cells.

The footer can also be used to include otherwise important yet ancillary information, such as the sum total of each cell when dealing with numerical values.

It's obviously not the case in our example, so I went with the first application.

You don't necessarily need to use all three elements we learned about (<thead>, <tbody> and <tfoot>). I only recommend them for larger and more complex tables that need to be divided, for simple tables you can just skip them entirely. When none of these tags are present, the table is interpreted as if it consisted entirely of a <tbody> section.

Merging table cells

We learned how to build simple tables, complex tables and even how to stylize our cells using CSS.

What could be left to cover in this chapter?

Merging cells.

Both header cells <th> and data cells <td> can be merged horizontally or vertically using either one, or both, of these HTML attributes.

  • colspan : defines how many columns a cell can occupy
  • rowspan : defines how many rows a cell can occupy

The default value of both these attributes is 1.

If I wanted one of my tables cells to take up two "spaces" horizontally, I would write: <td colspan="2">.

But the best way to understand how these attributes work is through a practical example.

Let's adjust our demonstration table into the following.

<table>
    <tr>
        <th></th>
        <th scope="col">Markup?</th>
        <th scope="col">Style?</th>
        <th scope="col">Awesome?</th>
    </tr>

    <tr><th scope="row">HTML</th><td>Yes</td><td>Deprecated</td><td>No</td></tr>

    <tr><th scope="row">CSS</th><td>No</td><td>Yes</td><td>No</td></tr>

    <tr><th scope="row">SiteRaw</th><td>No</td><td>No</td><td>Yes</td></tr>
</table>

You can see the result below.

A regular table
A regular table

As you can see, there are a few adjacent cells that contain the same information: the last cells of the first two rows and the first two cells of the last row.

We can merge them together using the HTML attributes we just discovered.

<tr>
    <th>HTML</th>
    <td>Yes</td>
    <td>Deprecated</td>
    <td rowspan="2">No</td>
</tr>

<tr>
    <th>CSS</th>
    <td>No</td>
    <td>Yes</td>
</tr>

<tr>
    <th>SiteRaw</th>
    <td colspan="2">No</td>
    <td>Yes</td>
</tr>

I removed the scope attributes (they are optional) so you could see more clearly to which cells colspan and rowspan are applied.

Here is the result.

A table with merged cells
A table with merged cells

As you can see, two pairs of cells have been merged: horizontally on the bottom left and vertically on the top right.

You aren't limited to merging only two cells, you can apply whatever value you want to these attributes provided it doesn't surpass the total number of available cells per line or column.

You can also apply both attributes to the same cell if you ever need to (you won't).

When the value of either colspan or rowspan is greater than 1, meaning that the cell takes up more than its default allocated space, you have to manually adjust your table by removing the now duplicate cells on other lines or columns. In our code example, you can see that some row have "missing" cells.

You thought this chapter was over?

Think again!

Allow me to introduce... multidimensional 4D tables!!! With HTML physical chairs and sheeit.

[...] On second thought, that may be too advanced even for you.

Better move on to the next chapter.