Here’s a fabulous CSS trick from Bradley Taunt in which he shows how to make tables work on mobile with just a little bit of extra code. He styles each table row into a card that looks something like this:
See the Pen
Responsive Tables #2.5: Flexbox by Bradley Taunt (@bradleytaunt)
on CodePen.
(Make sure to grab the Pen and make it a bit smaller to see how the design works responsively.)
Bradley’s example markup looks like this – clean, accessible, regular ol’ HTML:
<table>
<thead>
<tr>
<th>Type of Food</th>
<th>Calories</th>
<th>Tasty Factor</th>
</tr>
</thead>
<tbody>
<tr>
<td><span>Type of Food</span> Slice of Pizza</td>
<td><span>Calories</span> 450</td>
<td><span>Tasty Factor</span> 95%</td>
</tr>
</tbody>
</table>
How does he make that card effect? He uses flexbox on smaller screens and sets the span
elements to reveal themselves.
However! I’m not a big fan of those spans. They’re hidden on larger screen sizes but the markup is still there, so it doesn’t feel particularly clean to me. I was working on a project a little while ago where we stumbled on the same problem. We decided to use data attributes on each td
instead, like this:
<table>
<thead>
<tr>
<th>Type of Food</th>
<th>Calories</th>
<th>Tasty Factor</th>
</tr>
</thead>
<tbody>
<tr>
<td data-title="Type of Food">Slice of Pizza</td>
<td data-title="Calories">450</td>
<td data-title="Tasty Factor">95%</td>
</tr>
</tbody>
</table>
Then we can grab that data attribute in our styles and render it on the page in a pseudo element:
td:before {
content: attr(data-title);
}
From there we absolutely position the pseudo element to the side and only show it on smaller screens with a media query. I’m uncertain about the accessibility implications of this but it just feels a bit easier to read and understand in my opinion.
Either way, I think this post is a great reminder about all the tricky issues that pop up once you start using tables. There’s so many ways to handle things responsively and those decisions should entirely be made on the context of the design.
Responsive tables…
When you need to compare data up and down columns, it's probably best to largely leave the table structure alone and allow scrolling.
If each row can be broken apart and still be useful, collapsing them to avoid scrolling is nice.https://t.co/zeMFdrwU1M pic.twitter.com/3z8hQDvNAZ
— CSS-Tricks (@css) October 11, 2019
If you need to compare each food, you can transpose that table (putting type of food as columns) and use a similar technique with
attr(data-title)
but using the type of food as value on each cell.That way, on mobile your table will look like this:
Calories
Slice of Pizza 450
Hamburger 350
Tasty Factor
Slice of Pizza 95%
Hamburger 87%
Please ensure you add correct
role
s to each element of a table that you change thedisplay
of when you’re changing it to a non-table type.Tables are a bit of a special case when it comes to the
display
CSS property, as it affects how it is added to the accessibility tree and what the options a users screen reader has on it.In the above examples, you’ve changed the
<tr>
to have have adisplay: flex
, which means that the<tr>
and all child<th>
and<td>
elements will need to have appropriaterole
attributes added (yes, to each and every element affected). Without this, the table won’t present itself as a table correctly in the accessibility tree.