Many things can be done to make an HTML table accessible: add a <caption>
, use semantic HTML (<thead>
, <tbody>
, <tfoot>
...), associate date with the right headers (using role
, id
and headers
)...
Most of those changes will go on the HTML side, but some things can be done exclusively on CSS to improve the accessibility and usability of tables.
Let's see them starting with an example:
<table>
<thead>
<tr>
<th>Col1</th> <th>Col2</th> <th>Col3</th>
</tr>
</thead>
<tbody>
<tr>
<td>ABC</td> <td>DEF</td> <td>GHI</td>
</tr>
<tr>
<td>JKL</td> <td>MNO</td> <td>PQR</td>
</tr>
<tr>
<td>STU</td> <td>VWX</td> <td>YZ.</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>123</td> <td>456</td> <td>789</td>
</tr>
</tfoot>
</table>
That code will generate a table like this one on most browsers:
This is a table with no styles whatsoever. And needless to say, it looks terrible. Many issues need to be addressed to improve accessibility and usability in general. Sighted users (even ones with 20/20 vision) will have many problems:
- It's tough to differentiate table head rows from the rest of the rows (even with the bold from the
<th>
). - Content within the rows is too close together, and it may not be easy to see where a column ends, and the next one starts.
- In bigger tables, users could "lose track" of the line and jump between lines.
- It's impossible to differentiate between rows in the table body and rows in the table footer.
This post will review some easy fixes for those issues and how they can be implemented just on the CSS side.
1. Add spacing between the content
Adding space will help unclutter and unclog the table. We can achieve this by adding padding to the table cells –and don't forget the <th>
too:
th, td {
padding: 0.5rem 1rem;
}
The original table with this change will look like this:
Note that the padding values could be adjusted to make the separation bigger or smaller, but at this point, the table columns are clearly differentiated and obvious, which was our goal.
To better differentiate the content, we could have gone for a different approach adding borders in the table –and that would have addressed several of the issues noted above–, but personally, the result is still subpar and would require some of the suggestions below to make it look better.
2. Add a visual separation between table regions
The only visual indication that the first row is a header is that the text is written in bold letters. This happens because we are using <th>
. If he used <td>
instead, it would be impossible to say.
The same thing happens with the <tfoot>
; it is visually impossible to know if the last row is a table footer or another row in the <tbody>
.
One thing that can be done is adding a line below the <thead>
and above the <tfoot>
. We could do that by applying a border to the head and foot cells, but that could lead to (easily solvable) problems.
Another option is using a box-shadow
that will be applied to the thead
and tbody
elements. Like this:
thead {
box-shadow: inset 0 -2px;
}
tfoot {
box-shadow: inset 0 2px;
}
Now you can clearly distinguish what the head, the body, and the footer in our table are:
While the sections are easily identifiable, if the table had many rows and columns, users reading data horizontally may jump from line to line and lose track of where they are.
3. Add a distinction between consecutive rows
To avoid this jumping from line to line and from row to row, we can change the row color alternatively. To do so, we can target odd rows using :nth-child(odd)
and even rows by using :nth-child(even)
:
table > tr:nth-child(even),
tbody tr:nth-child(even) {
background: rgba(0,0,0,0.05);
}
table > tr:nth-child(odd),
tbody tr:nth-child(odd) {
box-shadow: 0 -1px rgba(0,0,0,0.1), 0 1px rgba(0,0,0,0.1);
}
As you may have noticed, if you applied the code above, it leaves a small spacing between rows that doesn't look great. To avoid it, we can collapse the borders:
table, thead, tbody, tfoot, tr, td, th {
border-collapse: collapse;
}
Which will generate this table:
Now our table has clearly separated sections, and the alternating rows make the content easier to follow.
4. Add highlight to active/hovered row
One final touch would be highlighting the row that is currently "active" or, more specifically, where the mouse is over.
We do by applying a different background on the :hover
state of each row:
table > tr:hover,
tbody tr:hover {
background: #bdf;
}
Now we have the same table as before, but when we move the mouse over each row, it is displayed in a shade of blue:
And with this one, we are done. As you may have noticed, these tips and tricks are not specific to accessibility, but more related to the table's visualization and its usability.
They will impact how sighted, and low-vision users interact and with the tables. And in that sense, they are important for accessibility too.
Create tables in which the data is clearly sorted and distinguishable.
Top comments (3)
nice article, thanks. i like flaviocopes.com/css-responsive-table/ which i recall seeing earlier done by someone else, but basically, change the axis of the table headers according to the device once semantics have been properly placed. make the headers float or slide out like a sidebar on small devices, or make them disappear altogether and become headers on each
<td>
if hovered/tapped/pressed/etc/ and use aria-pressed, etc, etc. anything.also according to the W3C specs,
<tfoot>
has to come before<tbody>
Thanks! That is a good one too. I will edit the article adding a similar method (providing reference)
welcome