LOG IN

Forgot Your Password?


Incorrect login or password

SIGN UP



Existing user?

Forgot Password


Existing user?

HTML Tables

HTML Tables

This chapter covers HTML tables, including everything you need to know about how to markup various use cases. All the major table elements and attributes are covered, including table headers, footer, body, and columns. This chapter provides concrete suggestions for dealing with some of the difficulties built in to the table markup and touches on real world practices.

What are tables?

A table in HTML is a way to present “tabular data” — information that can be represented in a spread-sheet. Tables in HTML are two dimensional tables with rows and columns.

First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41

Tabular data comes in many forms. The easiest way to tell if something should be in a table, as opposed to a different syntax like definition list, is to ask yourself, “Would this make sense as a spreadsheet?”

If data would make sense as a spreadsheet, it is a good candidate for a table.

Table Syntax

Basic Syntax

All tables use the <table> element, the table row ( <tr> ) element, and the table cell ( <td> ) element.

These three elements alone are enough for a simple table. A table is built one row ( <tr> ) at a time.

<table> <tr>  <td>John</td>  <td>Smith</td>  <td>31</td> </tr> <tr>  <td>Jane</td>  <td>White</td>  <td>32</td> </tr> <tr>  <td>Terry</td>  <td>Jones</td>  <td>41</td> </tr> </table>
John Smith 31
Jane White 32
Terry Jones 41

Table Headers: Option 1

It is often desirable to put headers at the top of a table. One way of doing this is to replace normal table cells ( <td> ) with table header cells ( <th> ).

<table> <tr>  <th>First Name</th>  <th>Last Name</th>  <th>Age</th> </tr> <tr>  <td>John</td>  <td>Smith</td>  <td>31</td> </tr> <tr>  <td>Jane</td>  <td>White</td>  <td>32</td> </tr> <tr>  <td>Terry</td>  <td>Jones</td>  <td>41</td> </tr> </table>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41

The benefit of this approach is that you it doesn’t affect the entire row, only those cells which are designated as headers. That is — it’s a benefit if that’s what you want to happen.

Table Headers (and Body): Option 2

The other way to make table headers is to wrap the entire first row (or several rows, even) in a table-head ( <thead> ) element.

When this is done, the rest of the content is usually wrapped in a table-body ( <tbody> ) element.

<table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>  </tr>  <tr>   <td>Jane</td>   <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>  </tr> </tbody> </table>

Doing this allows the entire header row to be styled.

 thead {  background-color: black;  color: white;  font-weight: bold; }
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41

Perhaps more interestingly, this also allows the body of the table to be styled without affecting the head.

tbody tr:nth-child(odd) {     background-color: #eee; } tbody tr:nth-child(even) {    background-color:#fff; }
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41

Table Footer

Along with a table head and a table body, you can also define one or more rows as belonging to a table footer ( <tfoot> ). This is useful if you need to style the last row differently than the other rows. Most commonly, this might be used if the last row is a summation or calculation based on the rows above it.

<style> thead {  background-color: black;  color: white;  font-weight: bold; } tbody tr:nth-child(odd) {  background-color: #eee; } tbody tr:nth-child(even) {  background-color:#fff; }  tfoot {  background-color: #222222;  color: white;  font-style: italic; }  </style> <table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>  </tr>  <tr>   <td>Jane</td>   <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>  </tr> </tbody> <tfoot>  <tr>   <td></td>   <td>Average Age</td>   <td>34.67</td>  </tr> </tfoot> </table>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41
  Average Age 34.67

Table Columns

Sometimes you need to style a table column. This can be achieved (to some extent) by using column markup.

Columns work a little strangely in HTML. Since tables are written as a series of rows, columns are define as a secondary overlay on the table.

At the top of the table, the <colgroup> element defines how columns will be laid over the table. Inside the <colgroup> are individual column definitions, using the <col> element. Each <col> spans one or more columns and defines a stylable entity.

<colgroup>  <col style="background-color: cyan;">  <col style="background-color:yellow;">  <col style="background-color:red;"> </colgroup> <table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>  </tr>  <tr>   <td>Jane</td>   <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>  </tr> </tbody> <tfoot>  <tr>   <td></td>   <td>Average Age</td>   <td>34.67</td>  </tr> </tfoot> </table>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41
  Average Age 34.67

Each <col> in the example above spans one column of table cells. If we wanted to apply styles to the two name columns as a single unit, we could make the <col> span two cell columns.

<colgroup>  <col span="2" style="background-color: cyan;">  <col style="background-color:yellow;"> </colgroup> <table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>  </tr>  <tr>   <td>Jane</td>    <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>  </tr> </tbody> <tfoot>  <tr>   <td></td>   <td>Average Age</td>   <td>34.67</td>  </tr> </tfoot> </table>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41
  Average Age 34.67

There are problems with using the <colgroup> markup, unfortunately:

  • <col> only supports styles related to background, width, border, and visibility. This means you cannot, for example, style the first column of a table in bold.

  • Because <col> is neither a parent nor a child element of any table sections (head, body, footer), you cannot target a specific column within a section.

  • Moreover, the table sections and table rows are more specific than the <col> element, so styles applied to the sections will override any style applied to the

Because of these issues, <col> has limited usefulness for table styling.

There are two common solutions to this: class attributes and nth-child selectors.

To use class attributes, simply apply the column-specific class to each <td> (and/or <th>) element.

<table> <thead>  <tr>   <th class="col1">First Name</th>   <th class="col2">Last Name</th>   <th class="col3">Age</th>  </tr> </thead> <tbody>  <tr>   <td class="col1">John</td>   <td class="col2">Smith</td>   <td class="col3">31</td>  </tr>  <tr>   <td class="col1">Jane</td>   <td class="col2">White</td>   <td class="col3">32</td>  </tr>  <tr>   <td class="col1">Terry</td>   <td class="col2">Jones</td>   <td class="col3">41</td>  </tr> </tbody> <tfoot>  <tr>   <td class="col1"></td>   <td class="col2">Average Age</td>   <td class="col3">34.67</td>  </tr> </tfoot> </table>

Of course, this adds a lot of markup which isn’t strictly required. A better way would be to use the :first-child, :nth-child, and :last-child CSS selectors.

For example, what if we wanted the First Name column to be bold, and the ages to display in a red,monospace font — along with the other header and footer styles defined earlier?

<style> thead {  background-color: black;  color: white;  font-weight: bold; } tbody tr:nth-child(odd) {  background-color: #eee; } tbody tr:nth-child(even) {  background-color:#fff; }  tfoot {  background-color: #222222;  color: white;  font-style: italic; }  td:first-child {  font-weight: bold; }  td:last-child {  font-family: monospace;  color: red; }  </style> <table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>  </tr>  <tr>   <td>Jane</td>   <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>  </tr> </tbody> <tfoot>  <tr>   <td></td>   <td>Average Age</td>   <td>34.67</td>  </tr> </tfoot> </table>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41
  Average Age 34.67

Breaking the Grid: rowspan and colspan

Sometimes your tabular data doesn’t fit neatly into the grid created by a table. If you need a table cell to span two or more columns, use the colspan attribute. If you need to span more than one row, use rowspan.

For example, our table of ages has a footer row with a label for “Average Age.” This doesn’t need to be squashed into the second column. It would look better if the label span the first two cells in the last column.

<tfoot>  <tr>   <td colspan="2">    Average Age:   </td>   <td>    34.67   </td>  </tr> </tfoot>
First Name Last Name Age
John Smith 31
Jane White 32
Terry Jones 41
Average Age 34.67

A similar syntax can be used to span two rows. (We’ll have to add a column for this, since we don’t have any good candidates for cell-merging.)

<table> <thead>  <tr>   <th>First Name</th>   <th>Last Name</th>   <th>Age</th>   <th>Cohort</th>  </tr> </thead> <tbody>  <tr>   <td>John</td>   <td>Smith</td>   <td>31</td>   <td rowspan="2">Oregon Trail Generation</td>  </tr>  <tr>   <td>Jane</td>   <td>White</td>   <td>32</td>  </tr>  <tr>   <td>Terry</td>   <td>Jones</td>   <td>41</td>   <td>Generation X</td>  </tr> </tbody> <tfoot>  <tr>   <td colspan="2">Average Age</td>   <td>34.67</td>   <td>  </tr> </tfoot> </table>
First Name Last Name Age Cohort
John Smith 31 Oregon Trail Generation
Jane White 32
Terry Jones 41 Generation X
Average Age 34.67  

What are tables not?

It shouldn’t really have to be said, but:

Tables are not for layout. Tables should not be used as a convenient way to make columns and headers at the level of a whole document.

This is sometimes still an issue today because before the era of standards-based web browsers and semantic markup, many people used tables (with a lot of complex style rules) to layout HTML documents.

This was a bad idea for a number of reasons, even then: it made the source document almost unreadable, it broke semantics completely, it made it nearly impossible to restyle a page without recoding all of it.

Today there is a new reason to avoid this — a reason that trumps all the others: it doesn’t work on mobile. Table-based layout is definitively not responsive, incapable of gracefully scaling to fit various screen sizes.

Besides all of that — compared to the right way of doing things, table-based layout is much more difficult. Just don’t do it.

Table Edge Case — side-by-side translations

One non-data use for tables that is fairly common is side by side translation. Consider the following excerpt from Dante’s The Divine Comedy.

Nel mezzo del cammin di nostra vita
mi ritrovai per una selva oscura,
ché la diritta via era smarrita.
Midway upon the journey of our life
I found myself within a forest dark,
For the straightforward pathway had been lost.
Ahi quanto a dir qual era è cosa dura
esta selva selvaggia e aspra e forte
che nel pensier rinova la paura!
Ah me! how hard a thing it is to say
What was this forest savage, rough, and stern,
Which in the very thought renews the fear.
Tant’ è amara che poco è più morte;
ma per trattar del ben ch’i’ vi trovai,
dirò de l’altre cose ch’i’ v’ho scorte.
So bitter is it, death is little more;
But of the good to treat, which there I found,
Speak will I of the other things I saw there.

This is, of course, merely a table with a little styling:

<style> #inferno-opening { border: none; border-spacing: 10px;  }  </style>  <table id="inferno-opening"> <tr> <td> Nel mezzo del cammin di nostra vita <br> mi ritrovai per una selva oscura, <br> ché la diritta via era smarrita. <br> </td><td> Midway upon the journey of our life <br> I found myself within a forest dark, <br> For the straightforward pathway had been lost. <br> </td> </tr> <tr> <td> Ahi quanto a dir qual era è cosa dura <br> esta selva selvaggia e aspra e forte <br> che nel pensier rinova la paura! <br> </td> <td> Ah me! how hard a thing it is to say <br> What was this forest savage, rough, and stern, <br> Which in the very thought renews the fear. <br> </td> </tr> <tr> <td> Tant’ è amara che poco è più morte;<br> ma per trattar del ben ch’i’ vi trovai,<br> dirò de l’altre cose ch’i’ v’ho scorte.<br> </td> <td> So bitter is it, death is little more;<br> But of the good to treat, which there I found,<br> Speak will I of the other things I saw there.<br> </td> </tr> </table>

The benefit of using tables in this example is that each row automatically adjusts it’s height based on the content in all the cells in the row. This keeps translated content next to its source, even if one language is more verbose than the other.

Many developers use this pattern for translated text, and it is perfectly fine. However, there may be a better way.

Consider the following HTML:

<div id="canto-1">  <div class="italian">   <p id="it-1" class="p1">   Nel mezzo del cammin di nostra vita <br>   mi ritrovai per una selva oscura, <br>   ché la diritta via era smarrita. <br>   </p>   <p id="it-2" class="p2">   Ahi quanto a dir qual era è cosa dura <br>   esta selva selvaggia e aspra e forte <br>   che nel pensier rinova la paura! <br>   </p>   <p id="it-3" class="p3">   Tant’ è amara che poco è più morte; <br>   ma per trattar del ben ch’i’ vi trovai, <br>   dirò de l’altre cose ch’i’ v’ho scorte. <br>   </p>  </div>  <div class="english">   <p id="en-1" class="p1">   Midway upon the journey of our life <br>   I found myself within a forest dark, <br>   For the straightforward pathway had been lost. <br>   </p>   <p id="en-2" class="p2">   Ah me! how hard a thing it is to say <br>   What was this forest savage, rough, and stern, <br>   Which in the very thought renews the fear. <br>   </p>   <p id="en-3" class="p3">   So bitter is it, death is little more; <br>   But of the good to treat, which there I found, <br>   Speak will I of the other things I saw there. <br>   </p>   </div> </div>

Using CSS to float the two languages next to each other, and JS to ensure that each pair of paragraphs (en-1 and it-2, etc.) is the the same height, the same effect can be created without recourse to table-based layout.

Advantages:

  • Some screens may not be wide enough to fit both text-columns side-by-side. Using this approach, one or the other can be viewed individually.
  • This allows multiple paragraphs of one text to be selected for copy-and-paste. With the table-based version, this is not possible.

Disadvantages:

  • Requires JavaScript
  • Each paragraph must be IDed in the markup.

Tables in the Real World

The default styles for tables are really quite unattractive, and therefore seldom used. Most front-end UI frameworks (like Bootstrap and Skeleton) provide highly improved default table styling.

Even if you aren’t using a front-end UI framework, it may be a good idea to pull in the styles for tables from one of the light-weight, modular frameworks. Tables have a lot of weird styling edge cases that you probably won’t cover if you try to fix the styling yourself from scratch.

Summary

Tables are probably the most complicated markup structure in HTML, and they have been abused in the past in order to serve as containers for layout. However, when tabular data needs to be displayed on a page, tables are the way to go.

“source: http://www.whoishostingthis.com/resources/html-for-beginners/”


 << Previous  Next >>