Internet Performance Delivered right to your inbox

Responsive CSS Table Design In Practice & Execution

We recently launched a new DNS Product feature comparison table to help users more easily compare our DNS products and what they offer. I’m eager to make all of this content accessible for people on smaller screens (particularly people on mobile devices), but it’s very hard to make tables look as good as they do on wider screens.

Here’s what we did and how we did it.

nth-of-type:before trick

I came across this post on CSS Tricks about how to build responsive tables by adding content to each table cell in a media query for smaller screen sizes. Basically, you eliminate the main table header row and add that content back in to each individual cell so that it’s easily scanned on a smaller screen. This technique uses nth-of-type to count through tds and add content, which works great on simple tables.

Unfortunately, I have a much more complex one:

If I didn’t have any table cells that spanned multiple columns, I could just use CSS Trick’s :before trick for each column and I’d be all set. But because we have some column spans, the count of table cells gets wonky.

For example: in the first row of data below the header, the same information spans DynECT Managed DNS Lite 10, 25, and 50 cells. Therefore the fourth td in the row is the Enterprise table cell. In the next row, though, there are separate tds for Lite 10, 25, and 50, so the Enterprise cell data is in the sixth td. This means I can’t just find the fourth or sixth td to add the Enterprise label, so I needed to get a little creative!

nth-of-type and colspan*=x

First, set everything in the table to display block and automatically decide its width.

table, th, td, tr { display: block; text-align: left; width: auto; }

Next, hide the header row.

thead tr { position: absolute; top: -9999px; left: -9999px; }

Let’s set up our table cell headers with some styling. We’re using :before to add in the content, so I want to display that as a block-level element and bold our label text.

td:before { display: block; font-weight: bold; }

Time to add the labels! Here’s where we have to do some fancy counting. I primarily use two kinds of selectors:

  • td:nth-of-type(x) which finds the nth td in the row
  • td[colspan*="x"] which finds all tds that have a particular column span

Let’s start easy. The first cell is most likely DynDNS Pro:

td:nth-of-type(1):before { content: "DynDNS Pro: "; }

The second td is most likely Standard DNS:

td:nth-of-type(2):before { content: "Dyn Standard DNS: "; }

But sometimes, we combine DynDNS Pro and Standard DNS in the same cell. In this case, we can target it knowing it spans two columns:

td[colspan*="2"]:before { content: "DynDNS Pro and Dyn Standard DNS: "; }

Moving along, let’s figure out how to best target DynECT Managed DNS Lite. It’s often the third td, so we should catch that. It may also be the fourth and fifth tds in the case where we split out the tier information, so let’s grab that.

We also have a case where it spans the third, fourth and fifth tds using colspan=3, so we target that too.

{ content: "DynECT Managed DNS Lite: "; }

Let’s use the cascading part of CSS to replace any previously incorrectly named DynECT Managed DNS cells (such as when it’s the fourth td) to its correct name:

td:last-of-type:before { content: "DynECT Managed DNS: "; }

And lastly, let’s use the same cascading technique to catch any of the four-column spans, which always will have the same label:

td[colspan*="4"]:before { content: "DynECT Managed DNS Lite and DynECT Managed DNS: "; }

And that takes care of it! We used the power of nth-child, colspan, and cascading power to add content in each td that clearly labels what original column header it applied to. You can see what the end result looks like on the right!

Share Now

Whois: Dyn Guest Blogs

Oracle Dyn is a pioneer in managed DNS and a leader in cloud-based infrastructure that connects users with digital content and experiences across a global internet.

To current Dyn Customers and visitors considering our Dynamic DNS product: Oracle acquired Dyn and its subsidiaries in November 2016. After June 29th, 2020, visitors to will be redirected here where you can still access your current Dyn service and purchase or start a trial of Dynamic DNS. Support for your service will continue to be available at its current site here. Sincerely, Oracle Dyn