Displaying Tables As Block Elements On Mobile

The experience of using tables in websites whilst on a mobile can be pretty poor. Things tend to get a bit squashed and displaying the information can be a challenge just to fit the table onto the screen.

I was recently faced with a similar problem where I had a particular design in mind for the mobile version of the table. The solution I found was base based on some responsive table designs from CSS-tricks. I'm certainly no designer, but the what I created worked for the situation I was trying to solve.

The basic idea is that instead of treating the table like a table, change all of the table elements to block elements when displaying on mobile. This meant that when viewing the table in a mobile view it would be rendered in a different way, allowing it to be shown in a mode that was more mobile friendly.

Let's use the following table filled with some data.

<table>
<thead>
  <tr>
    <th>Title</th>
    <th>Published</th>
    <th>Author</th>
    <th>Pages</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th>Dirk Gently's Holistic Detective Agency</th>
    <td>1987</td>
    <td>Douglas Adams</td>
    <td>306</td>
  </tr>
  <tr>
    <th>The Long Dark Tea-Time of the Soul</th>
    <td>1988</td>
    <td>Douglas Adams</td>
    <td>256</td>
  </tr>
  <tr>
    <th>The Meaning of Liff</th>
    <td>1983</td>
    <td>Douglas Adams, John Lloyd</td>
    <td>191</td>
  </tr>
  </tbody>
</table>

Along with the following CSS rules.

td {
  padding:1rem;
}
table tr th {
  font-weight: bold;
}
table tr:nth-child(even) {
    background-color: gray;
}

Adding this small bit of style to the table makes the headings bold and gives every even row has a grey background colour.

Responsive table block desktop

The first step in adding mobile CSS rules is to add in a media query that will kick in when the size of the browser window is 760px. The first thing we do in this media query is set all of the table elements to display as blocks on mobile.

@media only screen and (max-width: 760px)  {
  table,
  table thead,
  table tbody,
  table th,
  table td,
  table tr {
    display: block;
  }
}

The next step is to remove the header row from the table. What we are going to do is inject the header elements into the content of the table so having them appear above the text becomes redundant.

  table thead {
    display: none;
  }

The next part of this is to change each row of the table so that the first columns data floats above the other columns data. We do this by converting the other columns into inline blocks using the nth-of-type selector with an offset of one.

  table tbody tr td:nth-of-type(n+1) {
    display: inline-block;
  }

Finally, as we have hidden the header element we need to inject the headings back into the table content. This is done using a combination of the nth-of-type selector to pick the right element and the content style to inject the header before the content itself. Also, as we want the new heading text to float above the data we turn just the before content we have added into a block.

  table tbody tr td:before {
    font-weight: bold;
    display: block;
  }
  table tbody tr td:nth-of-type(1):before {
    content: "Published";
  }
  table tbody tr td:nth-of-type(2):before {
    content: "Author";
  }
  table tbody tr td:nth-of-type(3):before {
    content: "Pages";
  }

The combination of the inline-block with an inner block causes the heading text to float above the content and creates a perfect alignment of column header and data.

Now, when we resize the browser down to mobile view the table will change to be a different structure. Everything is still aligned correctly and the content is a little bit easier to read on a mobile.

Responsive table block mobile

This technique works best with data that has a long-ish text item as the first column as that forms a nice header element to the other data items. Also, it's best not to have too many columns in the table as it might look a bit cluttered. The good thing about this is that the headings will always align with the text due to them being pseudo-elements that sit right above the data.

There might be some more padding and other refinements that could be done here, but I wanted to reduce the CSS down to the absolute minimum of what is actually needed to get this working.

If you want to see this in action then I have created a codepen that has everything you need ready to copy.

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
1 + 2 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.