When building a
responsive website where the main responsibility is to display data in tables,
one needs to put some thought into how to present this data on smaller screens.
Tables are, of course, as wide as the number of data columns, so this presents some
challenges with how to display it when the view width is limited.
Using Bootstrap's table-responsive
Bootstrap's
table-responsive
class offers one solution, where the table is given a horizontal scrollbar.
This is not ideal as it requires the user to scroll the table to see all the
data in a row. This can be done by touching the table but this is not obvious
and some users may think they need to use the scrollbar. This then reduces
usability when there are more than a few rows in the table - the user would
scroll to the bottom of the table before scrolling horizontally, leading to
some frustrating vertical scrolling if the data they are looking at is back up
at the top of the table.
Rotating the Data
The following is an
alternative approach. The idea is to "rotate" the data so that
columns become rows and rows become collections of rows. So this table:
Looks like this on a
smaller screen:
Achieving this with
CSS poses a couple of challenges. How do you lay out table header cells
vertically, and flow the data cells in this way? Well obviously you can't, so
you need to employ a couple of tricks.
The first thing to
do is set up a simple table. It can use the bootstrap table class as well as
our custom responsive-table class
(note this is different to the bootstrap
table-responsive class).
<table class="table responsive-table">
<thead>
<tr>
<th>Number</th>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
<th>Points</th>
</tr>
</thead>
<tbody>
<tr>
<td data-content="Number">1</td>
<td data-content="First Name">Sam</td>
<td data-content="Last Name">Smith</td>
<td data-content="Address">12
Smith Road</td>
<td data-content="Points">87</td>
</tr>
<tr>
<td data-content="Number">2</td>
<td data-content="First Name">Bob</td>
<td data-content="Last Name">Jones</td>
<td data-content="Address">99
Angle Street</td>
<td data-content="Points">43</td>
</tr>
<tr>
<td data-content="Number">3</td>
<td data-content="First Name">Terrence</td>
<td data-content="Last Name">Rogers</td>
<td data-content="Address">999
Letsby Avenue</td>
<td data-content="Points">85</td>
</tr>
<tr>
<td data-content="Number">4</td>
<td data-content="First Name">Lawrence</td>
<td data-content="Last Name">Burnfish</td>
<td data-content="Address">69
The Matrix</td>
<td data-content="Points">0</td>
</tr>
</tbody>
</table>
Of course in a real
scenario, this data would be dynamic.
Note the use of the
data attribute. We'll get to that shortly. Otherwise this is a basic table. No
css is required for the full screen version, unless you want to add some
formatting, as this is handled by bootstrap's table class.
The CSS
It's in the media
query where the magic happens. You will need to decide on your breakpoint size
depending on the expected minimum width of the table, which might depend on the
number of columns, and width of the data. For this example, we'll set the breakpoint
to 600 pixels.
@media only screen and (max-width: 600px) {
.responsive-table {
border-top:
1px solid #ccc;
}
.responsive-table th,
.responsive-table thead{
display: none;
}
.responsive-table, .responsive-table tbody, .responsive-table tr, .responsive-table td {
display: block;
}
.responsive-table tr {
border-bottom:
1px solid #ccc;
}
.responsive-table td {
/* important to override bootstrap */
padding-left: 50% !important;
border-top:
0 !important;
text-align: left;
position: relative;
border-bottom:
0;
}
/* Now like a table header */
.responsive-table td:before {
font-weight:
bold;
font-size: 0.85em;
position: absolute;
margin-left:
-50%;
width: 50%;
white-space:
nowrap;
content: attr(data-content);
}
}
Setting the display
property of the tr and td elements to block forces the cells to flow
vertically.
.responsive-table, .responsive-table tbody, .responsive-table tr, .responsive-table td {
display: block;
}
Each cell has left
padding of 50% which matches the width and negative margin-left of our td:before pseudo element:
margin-left: -50%;
width: 50%;
To display the table
headers we're hiding the actual th
elements and using the value of the data-content attribute of each table cell.
This is done using the td:before pseudo element and by setting the content css
property using attr(data-content).
.responsive-table td:before {
font-weight:
bold;
font-size: 0.85em;
position: absolute;
margin-left:
-50%;
width: 50%;
white-space:
nowrap;
content: attr(data-content);
}
The beauty of using
the data-* attribute is that you can set these in the html to something dynamic
such a javascript or @razor variable. As they will be the same for each row,
this means they can be set within the loop
which displays the rows.
Presentation
We're hiding the
borders on the table cells and setting a border-bottom on the table rows, so
that our data is neatly separated into a collection of rows. Notice the table itself has a top border,
just to frame it.
Browser compatibility
As this trick uses
media queries, and media queries only work in IE9+, we only need to ensure the
other features work in IE9+. (Below this the table will not refactor when the
screen shrinks anyway). Content, data-*,
and pseudo elements all work in ie9, but unfortunately negative margins don't,
and combined with position:absolute, which is essential, this causes a pretty
significant issue.
Of course this only
becomes a problem when an IE9 user (currently about 2% globally) reduces their
browser window, and won't be a problem on actual mobile devices which this
technique is targetted for, so it's up to you whether you decide to mitigate
this by putting the media query into a conditional statement.
Wrapping text in titles
Watch out for cell
titles with more than one word. These could wrap when the screen size is
reduced and will wrap onto the next line if you have white-space set to normal
in the td:before css. One way around this is to make your table cell heights
2em or more, although this obviously means all sub-rows will be double height
even when there isn't a large title.
Conclusion
Refactoring tables
to display vertially can be a very useful alternative technique for presenting
wide tables on smaller devices. The technique may require tailoring to your
specific data shape and presentation requirements, but overall the tables are
easy to read and interact with.
Resources