Responsive table layout

1 min read
87511 views

One of my pet peeves in web design is how tables are often not optimized for non-desktop experiences. Let’s say I’m viewing Wikipedia on my iPhone, I’m looking through the episode list for Star Trek: The Next Generation (I grew up in the 90’s — deal), and the table has a lot of columns and data. There ends up being a lot of back-and-forth side swiping, device flipping, and general annoyance as I muddle through that user experience.

It’s an issue that exists broadly across the web, even though there are several responsive table solutions available, including this simple, CSS-only pattern:

So what’s the roadblock for using this or another pattern? Time? Effort? How about a quick run-through so we can see for ourselves?

Where to start?

We’ll create the same table above with some generic HTML:

<table>
  <caption>Statement Summary</caption>
  <thead>
    <tr>
      <th scope="col">Account</th>
      <th scope="col">Due Date</th>
      <th scope="col">Amount</th>
      <th scope="col">Period</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Visa - 3412</td>
      <td>04/01/2016</td>
      <td>$1,190</td>
      <td>03/01/2016 - 03/31/2016</td>
    </tr>
  </tbody>
</table>

Our table has four columns. Let’s add some basic CSS selectors to better define the table layout:

table {
  border: 1px solid #ccc;
  border-collapse: collapse;
  margin: 0;
  padding: 0;
  table-layout: fixed;
  width: 100%;
}

table tr {
  background-color: #f8f8f8;
  border: 1px solid #ddd;
  padding: .35em;
}

table th,
table td {
  padding: .625em;
  text-align: center;
}

This might look like many other HTML tables you’ve worked with. And probably about now you’re asking, “But how do I get this responsive?”

Gettin’ responsive!

First, we’ll add a data-label attribute to each data cell with a value that represents that column’s name. That will be used for labeling purposes in the responsive layout.

<td data-label="Account">Visa - 3412</td>
<td data-label="Due Date">04/01/2016</td>
<td data-label="Amount">$1,190</td>
<td data-label="Period">03/01/2016 - 03/31/2016</td>

Now we can begin writing a CSS media query:

@media screen and (max-width: 600px) {
  table thead {
    border: none;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
  }
  
  table tr {
    border-bottom: 3px solid #ddd;
    display: block;
  }
  
  table td {
    border-bottom: 1px solid #ddd;
    display: block;
    text-align: right;
  }
  
  table td::before {
    content: attr(data-label);
    float: left;
  }
}

In smaller viewports the <tr> and <td> elements will display as block-level and not as table rows and cells. And the ::before pseudo-element now serves as a label.

Here’s our table (flip your device screen between portrait and landscape view):

See the Pen Simple Responsive Table in CSS by Matt Smith (@AllThingsSmitty) on CodePen.

That’s it? 😳

Yep, pretty much. At least for this example. Keep in mind that this is just one responsive table layout with relatively simple data content. You may have different use cases and more complex data to manage, so YMMV. But always consider the options for a better user experience.