Mobile Friendly Tables
Building a table that works well on smaller screens is tricky, but I've come up with a simple CSS-only approach that works well for the 80% use case.
An Example
Check out the example below by resizing your browser window:
Title | Artist | Album | Released |
---|---|---|---|
Our Song | Radiator Hospital | Something Wild | 2013 |
DEB | Thin Lips | Riff Hard | 2016 |
Crown Victoria | Lithuania | White Reindeer | 2017 |
Phoenix | Slaughter Beach, Dog | Birdie | 2018 |
Enter Entirely | Cloud Nothings | Life Without Sound | 2017 |
the cool | Oso Oso | The Yunahon Mixtape | 2017 |
How Simple | Hop Along | Bark Your Head Off Dog | 2018 |
Shark Smile - Edit | Big Thief | Shark Smile (Edit) | 2017 |
Raining in Kyoto | The Wonder Years | Sister Cities | 2018 |
Dead-Bird | McCafferty | Beachboy | 2014 |
I Never Wanted You | Headphones | Headphones | 2005 |
Your Best American Girl | Mitski | Puberty 2 | 2016 |
How It's Done
The first step to creating a good table is to ask yourself "Do I actually need to use a table?". Many times there's better ways to present tabular data than just a boring table, Steve Schoger has some great tips on organizing tabular data.
If it turns out you really do need a table, check out the code in the next section.
The Code
First, let's take a look at the markup:
<table class="table-collapse">
<thead>
<tr>
<th>Title</th>
<th>Artist</th>
<th>Album</th>
<th class="text-right">Release Date</th>
</tr>
</thead>
<tbody>
<tr>
<td data-heading="Title">Our Song</td>
<td data-heading="Artist">Radiator Hospital</td>
<td data-heading="Album">Something Wild</td>
<td data-heading="Release Date" class="text-right">2013</td>
</tr>
</tbody>
</table>
There's two important thing to note in the markup above:
- The
table-collapse
class will apply the collapsible behavior to the table. - The
data-heading
attribute on each<td>
element should describe the table cell data.
Now, for the CSS:
@media (max-width: 768px) {
.table-collapse {
width: 100%;
}
.table-collapse > tfoot,
.table-collapse > thead {
display: none;
}
.table-collapse > tbody,
.table-collapse > tbody > tr,
.table-collapse > tbody > tr > td,
.table-collapse > tbody > tr > th {
display: block;
width: auto;
}
.table-collapse > tbody > tr {
padding-top: 0.5em;
padding-bottom: 0.5em;
border-top: 1px solid theme('colors.gray.200');
}
.table-collapse > tbody > tr > th {
border: none !important;
padding: 0.25em 0.5em;
text-align: left !important;
}
.table-collapse > tbody > tr > th:first-child {
padding-left: 0.5em;
}
.table-collapse > tbody > tr > th:last-child {
padding-right: 0.5em;
}
.table-collapse > tbody > tr > td {
border: none !important;
padding: 0.25em 0.5em 0.25em 35%;
box-shadow: none !important;
text-align: left !important;
position: relative;
}
.table-collapse > tbody > tr > td:first-child {
padding-left: 35%;
}
.table-collapse > tbody > tr > td:last-child {
padding-right: 0.5em;
}
.table-collapse > tbody > tr > td::before {
content: attr(data-heading);
position: absolute;
top: 0.25em;
left: 0.5em;
width: 35%;
padding-right: 0.25em;
white-space: nowrap;
z-index: 1;
}
}
View the code for this table as a gist.
Thanks to the media query in the first line above these styles are applied when the browser window is less than or equal to 768px
wide. The table's header and footer are hidden and the cells in each row stack vertically using display: block
. Each of the table cells also have padding-left: 35%
which allows a healthy amount of space for the ::before
pseudo element to sit to the left of the cell's data using position: absolute
. The content: attr(data-heading)
line dynamically pulls text from the data-heading
attribute in the HTML and uses that text as a new label for the cell. The best part is the CSS attr()
function has support all the way back to IE 8 when used as a content
value.