Responsive Tables in Pure CSS

We recently overhauled our payment statement tables for mobile web in Merchant Center. Our goal was to meet the following requirements:

  • No javascript. You can find all sorts of plugins to but it’s nice to go with a pure CSS solution if at all possible.
  • The text must be localized so no storing plain text in the stylesheets, nullifying Chris Coyer’s recommendation though the end result is built upon his idea. Plus it’s nice to keep the content in the views where it belongs.
  • No adjusting the font-size to 8px and cramming everything in :)

Pseudo Elements and Data Attributes to the Rescue

Pseudo elements, specifically :before and :after, match the virtual first and last children of the selected element. Typically they are used to add cosmetic content like an arrow on a tooltip, create a pretty ribbon, or include an icon font. The uses go further though. You can pull in content from HTML data attributes using content: attr(data-label) on the before/after pseudo classes. With this in mind, let’s take a look at how we can reorganize the table structure on mobile devices, creating a more “card” like design.

So if we have the following basic table structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<table>
  <thead>
    <tr>
      <th>Payment</th>
      <th>Issue Date</th>
      <th>Amount</th>
      <th>Period</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td data-label="Payment">Payment #1</td>
      <td data-label="Issue Date">02/01/2015</td>
      <td data-label="Amount">$2,311</td>
      <td data-label="Period">01/01/2015 - 01/31/2015</td>
    </tr>
    <tr>
      <td data-label="Payment">Payment #2</td>
      <td data-label="Issue Date">03/01/2015</td>
      <td data-label="Amount">$3,211</td>
      <td data-label="Period">02/01/2015 - 02/28/2015</td>
    </tr>
  </tbody>
</table>

And use the following CSS to pluck the data attributes out for each td, targeting all devices below 600px using media queries

1
2
3
4
5
6
7
8
@media screen and (max-width: 600px) {
  table td:before {
    content: attr(data-label);
    float: left;
    text-transform: uppercase;
    font-weight: bold;
  }
}

We are able to turn this mess

into this (keeping the styling to a minimum)

Check out all of the code on codepen

Comments