Many people have explored responsive tables. The usual idea is turning the table into key-value pairs so that cells become rows and there are only 2 columns total, which fit in any screen. However, this means table headers need to now be repeated for every row. The current ways to do that are:

Duplicating content in CSS or via a data-* attribute, using generated content to insert it before every row.

Using a definition list which naturally has duplicated <dt>s, displaying it as a table in larger screens.

A few techniques that go in an entirely different direction are:

Hiding non-essential columns in smaller screens

Showing a thumbnail of the table instead, and display the full table on click

Displaying a graph in smaller screens (e.g. a pie chart)

I think the key-value display is probably best because it works for any kind of table, and provides the same information. So I wondered, is there any way to create it without duplicating content either in the markup or in the CSS? After a bit of thinking, I came up with two ways, each with their own pros and cons.

Both techniques are very similar: They set table elements to display: block; so that they behave like normal elements and duplicate the <thead> contents in two different ways:

Using text-shadow and creating one shadow for each row Using the element() function to duplicate the entire thead, styles and all.

Each method has its own pros and cons, but the following pros and cons apply to both:

Pros: Works with normal table markup

Works with normal table markup Cons: All but the first set of headers are unselectable (since neither shadows nor element()-generated images are real text). However, keep in mind that the techniques based on generated content also have this problem — and for all rows. Also, that the markup screen readers see is the same as a normal table. However, it’s still a pretty serious flaw and makes this a hack. I’m looking forward to seeing more viable solutions. Only works if none of the table cells wrap, since it depends on table cells being aligned with their headers.



Using text-shadow to copy text to other rows

Additional Pros: Works in every browser

Works in every browser Additional Cons: Max Number of rows needs to be hardcoded in the CSS, since each row needs another text shadow on <thead> . However, you can specify more shadows than needed, since overflow: hidden on the table prevents extra ones from showing up. Also, number of columns needs to be specified in the CSS (the --cols variable).

Demo



Using element() to copy the entire <thead> to other rows

Additional Cons: element() is currently only supported in Firefox 🙁

Demo

