Joshua Hibbert

Latest Articles

Getting Responsive Tables to Behave

Getting Responsive Tables to Behave

View an example

Tables can be tricky to work with and they aren’t nat­ur­ally respons­ive. Chris Coyier has a great write up on CSS-Tricks regard­ing respons­ive data tables, and although this addresses most issues, there are a couple that it doesn’t. Primarily, over­lap­ping text on small screens and get­ting labels to stack ver­tic­ally when they don’t fit horizontally.

It’s import­ant to note that this isn’t a one-size-fits-all type of solu­tion. Like respons­ive design in gen­eral, you have to base your media quer­ies on your con­tent; find out where your tables start to get messy and set your break­points accord­ingly. Here’s the markup for an example table and the base CSS that I use to ensure that the table works across all device sizes:

<table>
    <thead>
      <tr>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Hero Title</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td data-label ="First Name">Bruce</td>
        <td data-label ="Last Name">Wayne</td>
        <td data-label ="Hero Title">Batman</td>
      </tr>
      <tr>
        <td data-label ="First Name">Peter</td>
        <td data-label ="Last Name">Parker</td>
        <td data-label ="Hero Title">Spiderman</td>
      </tr>
      <tr>
        <td data-label ="First Name">Bruce</td>
        <td data-label ="Last Name">Banner</td>
        <td data-label ="Hero Title">The Hulk</td>
      </tr>
      <tr>
        <td data-label ="First Name">Clark</td>
        <td data-label ="Last Name">Kent</td>
        <td data-label ="Hero Title">Superman</td>
      </tr>
    </tbody>
</table>

table {
  border-collapse: collapse;
  width: 100%;
}
/* Stack rows vertically on small screens */
@media (max-width: first-break-point) {
  /* Hide column labels */
  thead tr {
    position: absolute;
    top: -9999em;
    left: -9999em;
  }
  /* Leave a space between table rows */
  tr + tr {
    margin-top: 1.5em;
  }
  /* Get table cells to act like rows */
  tr,
  td {
    display: block;
  }
  /* Leave a space for data labels */
  td {
    padding-left: 50%;
  }
  /* Add data labels */
  td:before {
    content: attr(data-label);
    display: inline-block;
    margin-left: -100%;
    width: 100%;
  }
}
/* Stack labels vertically on smaller screens */
@media (max-width: second-break-point) {
  td {
    padding-left: 0;
  }
  td:before {
    display: block;
    margin-left: 0;
  }
}

The main dif­fer­ence to the CSS-Tricks art­icle linked above is that I don’t abso­lutely pos­i­tion the data labels (the td:before selector), instead I keep them in the flow of the doc­u­ment to ensure that the text won’t over­lap. I keep everything aligned by using neg­at­ive mar­gin to off­set the labels into the empty space cre­ated by giv­ing the table cells a large amount of pad­ding on their left-hand side. By set­ting that pad­ding to 50% we can off­set the labels using a mar­gin of -100% and avoid hav­ing to do any maths.

Another change to the CSS-Tricks art­icle is the use of the second media query to trig­ger a ver­tic­ally stacked table in which labels are above the data instead of along­side it. This means that tab­u­lar data is still read­able, even on devices with small screens.

These are my tricks to get­ting tables to behave respons­ibly, what are yours?

Latest Work

Latest Projects