When tables are not structured accessibly, the data they contain can quickly become a meaningless sea of numbers, facts and figures to someone moving through them a cell at a time. Readers who cannot see the table cannot use visual cheats like checking the alignment and scanning back to the top headings to orient themselves as they go. Equivalent information needs to be encoded into the table to facilitate comprehension.
Headers
One of the primary aids for table navigation is the proper use of headers. Correctly identified and linked headers provide metadata the reader can call up as needed as they navigate the data points.
The simplest kinds of tables contain a single header for each column or row, and are typically handled by
assistive technologies (AT) without the need for extra information. The header cells need only be marked
using the th
element and the AT will be able to replay them when requested:
<table border="1">
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
…
</table>
If a table's header spans more than one row, a thead
element should be used to group all the
header rows (see Example 1). When more than one header applies to a column, a
headers
attribute should be attached to each of its cells to clarify for an AT which
headers apply. For example:
<table border="1">
<thead>
<tr>
<th id="sales" rowspan="4">Sales</th>
</tr>
<tr>
<th id="ub" rowspan="2">Ultrabooks</th>
<th id="tab" rowspan="2">Tablets</th>
</tr>
<tr>
<th id="ugross">Gross</th>
<th id="unet">Net</th>
<th id="tgross">Gross</th>
<th id="tnet">Net</th>
</tr>
</thead>
<tbody>
<tr>
<td headers="ugross sales ub">$100,000</td>
<td headers="unet sales ub">$12,500</td>
<td headers="tgross sales tab">$45,000</td>
<td headers="tnet sales tab">$5,250</td>
</tr>
</thead>
…
</table>
The headers
attribute identifies the cells that contain the header text by their
id
attribute value. The order in which the ids are included in the attribute determines
how the headings are to be announced or rendered to the reader, so care must be taken to ensure logical
playback results.
The ordering of the headers does not have to exactly match the markup if another ordering would make more sense. In the previous example. it will make more sense to the reader to announce "gross sales ultrabooks" than "sales ultrabooks gross".
More generally, whenever there is any ambiguity about which headings apply to a cell, a
headers
attribute should be attached (e.g., headers at the end of a row, mixed heading
rows and columns, etc.). (See Example 3.) Note that HTML5 no longer allows
the td
element to be used for headings (i.e., a td
element cannot be referenced
from the headers
attribute).
The scope
attribute can also be used to clarify relationships between headers and cells.
Whenever the headers are not in the first row or column of a table, this attribute should be attached to
the th
elements to clarify their directionality (to the row or column they belong to).
headers
attributes are not needed when the scope is clearly defined.
<table border="1">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<th scope="row">Heading</th>
</tr>
</table>
Captions and summaries
A caption should always be included to give context to a table. Never rely on the text surrounding explain the presence of a table, especially when the table is offset from the content.
For complex tables, including a summary of the structure for the reader before they enter the content can greatly assist comprehension, as well. HTML5 currently does not provide a mechanism to include this information in a programmatically deterministic way (i.e., so that someone can discover the information without hunting around manually for it).
Secondary content
If a table is not required to be read at the point of insertion (i.e., it is not part of the logical reading order), use a figure tag to enclose it.
Presentational layout
Tables should never be used to lay out documents. See the section on fixed layout positioning with CSS for more information on how to create these documents more accessibly.
Avoid using tables when all that the cells contain are lists of information (e.g., for placing information side-by-side, or where the first column in each row is a new unrelated header and the second a list of relevant to that topic). The extra table formatting is an unnecessary encumbrance to navigation.
The following table header
Shipping. | Stock. | Wages. | Weights. | Name of Colony. | |||
---|---|---|---|---|---|---|---|
Book, page. | Appx, page. | Book, page. | Appx, page. | Book, page. | Appx, page. | ||
… |
becomes:
<table border="1">
<thead>
<tr>
<th id="ship" colspan="2">Shipping.</th>
<th id="stock" rowspan="2">Stock.</th>
<th id="wages" colspan="2">Wages.</th>
<th id="wt" colspan="2">Weights.</th>
<th id="name" rowspan="2">Name of Colony.</th>
</tr>
<tr>
<th id="book1">Book, page.</th>
<th id="appx1">Appx, page.</th>
<th id="book1">Book, page.</th>
<th id="appx1">Appx, page.</th>
<th id="book1">Book, page.</th>
<th id="appx1">Appx, page.</th>
</tr>
</thead>
…
</table>
The following table shows a distance chart with the destinations defined at the end of the row:
Vancouver | Calgary | Saskatoon | Winnipeg | Toronto | Montreal | St. John's | |
---|---|---|---|---|---|---|---|
7323 | 6334 | 5838 | 5010 | 3141 | 2602 | St. John's | |
4271 | 3743 | 3232 | 2408 | 539 | 2602 | Montreal |
which would be marked up as:
<table border="1">
<tr>
<th scope="col">Vancouver</th>
<th scope="col">Calgary</th>
<th scope="col">Saskaton</th>
<th scope="col">Winnipeg</th>
<th scope="col">Toronto</th>
<th scope="col">Montreal</th>
<th scope="col">St. John's</th>
<td></td>
</tr>
<tr>
<td class="center">7323</td>
<td class="center">6334</td>
<td class="center">5838</td>
<td class="center">5010</td>
<td class="center">3141</td>
<td class="center">2602</td>
<td class="center"></td>
<th scope="row">St. John's</th>
</tr>
<tr>
<td class="center">4271</td>
<td class="center">3743</td>
<td class="center">3232</td>
<td class="center">2408</td>
<td class="center">539</td>
<td class="center"></td>
<td class="center">2602</td>
<th scope="row">Montreal</th>
</tr>
</table>
The following table with headers at the top of each column and beginning of each row:
% Families | 1929 | 1970 | 1997 | |||
---|---|---|---|---|---|---|
Lowest 20% | 3.5% | 3.5% | 5.5% | 5.5% | 4.2% | 4.2% |
… |
would be marked up as:
<table border="1">
<caption>Table IX.4 Income Distribution Among Families 1929-1997</caption>
<tr>
<th id="t4-pct">% Families</th>
<th id="t4-1929" colspan="2">1929</th>
<th id="t4-1970" colspan="2">1970</th>
<th id="t4-1997" colspan="2">1997</th>
</tr>
<tr>
<th id="t4-low20">Lowest 20%</th>
<td headers="t4-1929 t4-low20">3.5%</td>
<td headers="t4-1929 t4-low20">3.5%</td>
<td headers="t4-1970 t4-low20">5.5%</td>
<td headers="t4-1970 t4-low20">5.5%</td>
<td headers="t4-1997 t4-low20">4.2%</td>
<td headers="t4-1997 t4-low20">4.2%</td>
</tr>
…
</table>
Excerpt from: Basic Microeconomics — R. Larry Reynolds
table
elementThe following resources present HTML 4 techniques that may not all still be applicable:
Although table rendering is still problematic in ebooks, including images of tables instead of the actual data takes the content away from anyone who cannot see it.
Tables are a problem that still need solving in reading systems, as most reading systems aren't able to provide extended horizontal or vertical scrolling to facilitate rendering. As a result, large tables get rendered in the available space – leaving rows and columns to spill across page views – compromising the quality of the ebook for sighted readers in trying to aid accessible devices.
If you are going to include an image of a table, consider providing a link to a file containing the table markup. Readers with TTS playback available will be able to navigate the markup regardless of the rendering quality.
Some reading systems render pop-out content in browser windows, which can also improve reading for sighted readers unable to read images that render too small or blow out of the viewport.
See also this CSS-Tricks article on responsive tables for an alternate approach to visual table rendering based on the available screen size.