Cover image for Make readable table headers with CSS

Make readable table headers with CSS

cchana profile image Charanjit Chana Originally published at 1thingaweek.com ・3 min read

Originally posted on my blog

One thing I've always found tough to work with when it comes to responsive design is tables. Collapsing them on mobile is easy enough, but for data rich content you end up with stacked headers that don't provide the context you'd get on desktop.

So there are some solutions, but for long sets of tabular data, either it introduces more text to read or they're not really what I would consider truly responsive. But I recently had a light bulb moment after looking at the new calendar view for my website. Why not? concatenate the header content into a readable sentence? It would give an indication of what is in each row without having to repeat the content or introducing a horizontal scrollbar.

Traditional responsive table layout

Either by using JavaScript or revealing the right header at different break points, we could reveal a row that has the column titles bunched up together which would stack really nicely. This isn't that readable though and using JavaScript is an overhead that isn't required.

Improved responsive table layout

How do you make responsive headers more readable?
Let's take it from just a list of words

Ultimate responsive table layout

The solution isn't difficult, it's just about understanding the flexbox model and how pseudo elements work. By combining the two, we can easily chain the headers into a readable header like the example above. Here's the basic CSS you would need to achieve this:

/* Use flexbox to remove the headers from their columns */
table thead tr,
table tbody:first-child tr:first-child {
    display: flex;
    text-align: left;
/* Remove the right border from all but the last cell */
table thead tr th:not(:last-child),
table tr:first-child th:not(:last-child) {
    border-right: 0;
/* Let the last cell take up all of the available space, bringing all the content next to each other */
table thead tr th:last-child,
table tr:first-child th:last-child {
    flex: 1;
/* Remove any LEFT padding from all except the first cell */
table thead tr th:not(:first-child),
table tr:first-child th:not(:first-child) {
    padding-left: 0;
/* Remove any RIGHT padding from all except the last cell */
table thead tr th:not(:last-child),
table tr:first-child th:not(:last-child) {
    padding-right: 0;
/* Add a comma and a space before to all but the first cell */
table thead tr th:not(:first-child):before,
table tr:first-child th:not(:first-child):before {
    content: ',\00a0';
/* Add ' & ' before the last cell */
table thead tr th:last-child:before,
table tr:first-child th:last-child:before {
    content: '\00a0\0026\00a0';

I've created a more complex solution as a gist on GitHub that has the basic HTML and the CSS to remove white space and introduce an alternating background colour to make the table easier to scan. You should be able to lift the CSS and apply it to any table. There's a resizable demo I've added to JSFiddle so you can try it out there too.

Even if you don't use the <tbody> HTML tags, looks like all browsers inject it anyway. By default, the code is wrapped in a media query which means it only applies to screens less than 700px wide. Either remove that restriction or adjust it to whatever your needs are.

Posted on May 28 by:

cchana profile

Charanjit Chana


Full stack developer / UI/UX architect with a love for lightweight HTML and CSS (using SASS). Progressive Enhancement FTW!


markdown guide