CSS Styling Tutorial To Clean Up Your HTML Tables Today

Disclosure: Your support helps keep the site running! We earn a referral fee for some of the services we recommend on this page. Learn more

In our Tables Tutorial we created a table to present some data about the popularity of different content management systems. In this tutorial, we’re going to add some CSS styling to our table. This tutorial assumes that you have a solid understanding of CSS implementation. If you’re brand new to CSS you may struggle to follow along, and you’ll be better served by taking a few minutes to review our CSS tutorial before proceeding on with this Table Styling tutorial.

Table Improvements

Here’s our table code as we left it at the end of the Tables Tutorial:

<table>   <caption>Most Popular Content Management Systems</caption>   <thead>     <tr>       <th>CMS</th>       <th>Usage *</th>       <th>Change Since Jan 1</th>       <th>Market Share *</th>       <th>Change Since Jan 1</th>     </tr>   </thead>   <tfoot>     <tr>       <td>Totals</td>       <td>33.3%</td>       <td></td>       <td>76%</td>       <td></td>     </tr>     <tr>       <td colspan="5">* <strong>Usage</strong> is percentage of surveyed websites        that use the associated CMS. <strong>Market Share</strong> is the percentage        of surveyed websites powered by a CMS that use the associated CMS. For example,        25.8% of all surveyed websites use WordPress, and WordPress commands 59.1%        market share of the total CMS market.</td>     </tr>     <tr>       <td colspan="5">The data in this table is provided courtesy of        <a href="http://w3techs.com" target="_blank">W3Techs</a> and was captured in        February 2016. To learn more about this topic visit the        <a href="http://w3techs.com/technologies/overview/content_management/all"        target="_blank">overview of content management systems</a> from W3Techs.</td>     </tr>   </tfoot>   <tbody>     <tr>       <td>WordPress</td>       <td>25.8%</td>       <td>+0.2%</td>       <td>59.1%</td>       <td>+0.3%</td>     </tr>     <tr>       <td>Joomla</td>       <td>2.8%</td>       <td>No Change</td>       <td>6.4%</td>       <td rowspan="4">No Change</td>     </tr>     <tr>       <td>Drupal</td>       <td>2.2%</td>       <td>+0.1%</td>       <td>4.9%</td>     </tr>     <tr>       <td>Magento</td>       <td>1.3%</td>       <td>+0.1%</td>       <td>2.9%</td>     </tr>     <tr>       <td>Blogger</td>       <td>1.2%</td>       <td>No Change</td>       <td>2.7%</td>     </tr>   </tbody> </table> 

And here’s how our table looks before adding any additional CSS styling:

Most Popular Content Management Systems
CMSUsage *Change Since Jan 1Market Share *Change Since Jan 1
Totals33.3%76%
* Usage is percentage of surveyed websites that use the associated CMS. Market Share is the percentage of surveyed websites powered by a CMS that use the associated CMS. For example, 25.8% of all surveyed websites use WordPress, and WordPress commands 59.1% market share of the total CMS market.
The data in this table is provided courtesy of W3Techs and was captured in February 2016. To learn more about this topic visit the overview of content management systems from W3Techs.
WordPress25.8%+0.2%59.1%+0.3%
Joomla2.8%No Change6.4%No Change
Drupal2.2%+0.1%4.9%
Magento1.3%+0.1%2.9%
Blogger1.2%No Change2.7%

At the end of our previous tutorial, we identifed five things that we could do to further improve the table.

  1. The table caption could use some styling to add emphasis and draw attention.
  2. The explanation and attribution comments in the table footer need to shrink in size a bit so that they aren’t quite as prevalent.
  3. The first column entries could be styled differently from the rest of the table data cells.
  4. We may want to center the contents of our td elements.
  5. This table doesn’t look very good on a small screen. We should make some changes so that it renders a little better on smaller devices.

In this tutorial, we’re going to improve the performance of our table by adding CSS styles to accomplish all of these objectives.

Fonts in Tables

Styling Table Text

Let’s start by taking care of the text-styling. Here are the changes we want to implement:

  1. The caption needs to increase in size so that is it more prominent. Let’s also add some padding to the top and bottom of the caption to give it a little breathing room.
  2. The table heading elements need to increase in size just a little to make them stand out from the table data.
  3. We also want to increase the size of the first column of table data elements.
  4. The footer explanation and attribution text need to shrink in size just a bit so that it doesn’t detract from the table data but remain easily readable. We also want to make sure they remain left-aligned.
  5. We want to center the text in all of our td elements.

Adjusting Font Size

We can control font size using the font-size property like this:

/*Targets the caption text*/ table caption {   font-size: 1.5em;   padding: 10px 5px;   }  /*Targets the headings and first column*/ th, td:nth-child(1) {   font-size: 1.1em;   font-weight: 500;   }  /*Targets footer explanation and attribution*/ tfoot tr:nth-child(1n+2) {   font-size: .9em;   font-weight: normal;   text-align: left;   } 

We’ve used a special selector for two of these rulesets called nth-child. This selector is a powerful CSS tool which can be used to pinpoint elements based on their position relative to their parent element. There are a few different values you can use for the nth-child selector:

  • Numbers, such as 1, identify a specific child element. For example, we were able to target the first column of our table with the selector td:nth-child(1). This selector targets the td element that is the first child of its parent element. By picking the first td element in each row, we’ve targeted the first column.
  • Words like odd or even can be used to target every other child element.
  • Any formula using the format an+b can be used. In our case, we used 1n+2. This formula will target every child element that exists as a possible solution to that equation which includes every child element other than the first. For example:
    • Replace n with “0” and we get 1*0+2 = 2.
    • Replace n with “1” and we get 1*1+2 = 3.
    • Replace n with “2” and we get 1*2+2 = 4.
    • And so forth.

Centering Table Data

Centering our table data entries is as easy as adding a single CSS rule. While we’re at it, let’s also add a little padding around each table data entry to add a little whitespace to the entire table.

td {       text-align: center;       padding: 5px;       } 

With our CSS in place, when we load our table we can see that the font styling has been changed.

table.ex_table_1 caption { font-size: 1.5em; padding: 10px 5px; } .ex_table_1 th, .ex_table_1 td:nth-child(1) { font-size: 1.1em; font-weight: 500; } .ex_table_1 td, .ex_table_1 th { text-align: center; padding: 5px; } .ex_table_1 tfoot tr:nth-child(1n+2) td { font-size: .9em; font-weight: normal; text-align: left; }

Most Popular Content Management Systems
CMSUsage *Change Since Jan 1Market Share *Change Since Jan 1
Totals33.3%76%
* Usage is percentage of surveyed websites that use the associated CMS. Market Share is the percentage of surveyed websites powered by a CMS that use the associated CMS. For example, 25.8% of all surveyed websites use WordPress, and WordPress commands 59.1% market share of the total CMS market.
The data in this table is provided courtesy of W3Techs and was captured in February 2016. To learn more about this topic visit the overview of content management systems from W3Techs.
WordPress25.8%+0.2%59.1%+0.3%
Joomla2.8%No Change6.4%No Change
Drupal2.2%+0.1%4.9%
Magento1.3%+0.1%2.9%
Blogger1.2%No Change2.7%

A Look Back: How it Used to Be Done

Let’s take a break from the table we’ve been working on to take a look back at how things were done just a few years ago. This topic is of special interest to webmasters who have inherited an antiquated website with a lot of old HTML tables. In the past, it was common to use the obsolete <font> element to assign font styles to table elements. The problem with this method? It was horrendously tedious since the <font> element had to be added to each and every table cell. If you’ve ever looked at the source code of an antiquated website you might have seen a mountain of difficult-to-manage code that looks something like this:

<TABLE BORDER BGCOLOR=NAVY>   <TR>     <TH><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>fruit</FONT></TH>     <TH><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>state</FONT></TH>   </TR>   <TR>     <TD><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>apples</FONT></TD>     <TD><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>Washington</FONT></TD>   </TR>   <TR>     <TD><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>pineapples</FONT></TD>     <TD><FONT COLOR=WHITE FACE="Geneva, Arial" SIZE=6>Hawaii</FONT></TD>   </TR> </TABLE> 

Yikes. This can all be done a lot more easily with CSS. Let’s look at an example. The following CSS (nested inside an HTML style element or in an external style sheet creates a rule that applies to elements of the boldtable class, and also to <td> and <th> elements inside the boldtable class:

.boldtable, .boldtable td, .boldtable th {    font-family: sans-serif;   font-size: 20pt;   color: white;   background-color: navy; } 

Now, we can clean up that table HTML, add a single class to the table element, and control all of our table’s font styles with a single CSS ruleset.

<table class="boldtable">   <tr>     <th>fruit</th>     <th>state</th>   </tr>   <tr>     <td>apples</td>     <td>Washington</td>   </tr>   <tr>     <td>pineapples</td>     <td>Hawaii</td>   </tr> </table> 

If you we put that clean HTML together with those simple CSS rules, here’s what we get:

.boldtable, .boldtable td, .boldtable th{font-family: sans-serif; font-size: 20pt; color: white; background-color: navy;}

fruitstate
applesWashington
pineapplesHawaii

Thankfully, the <font> element was deprecated in HTML 4.01 all the way back in 1999 and made obsolete with the release of HTML5. If you happen to run across this element, don’t hesitate to remove it and replace it with a modern CSS alternative.

Formatting Borders and Backgrounds

After adding just a few text-styling adjustments, our table already looks much better. However, we can make it stand out even more by adjusting the borders and backgrounds. Here’s what we’re going to do:

  1. We’ll remove all table borders so that we can use colors rather than borders to create separation between our rows of data.
  2. A popular table styling effect is to alternate the background color of table rows. Let’s implement that style.
  3. The table heading will stand out if we apply a more striking background color. Let’s use a darker color to draw attention to our th elements.

We can make all of those things happen with the following CSS statements:

/*Remove the borders from all table elements*/ table, th, td {   border: none; }  /*Apply a background color to the table heading*/ thead {   background-color: #a7a37e; }  /*Apply a background color to every other row in the table body*/ tbody tr:nth-child(even) {   background-color: #efecca; }  /*Apply a background color to every other row in the table footer*/ tfoot tr:nth-child(odd) {   background-color: #efecca; } 

You probably noticed that we’re using the nth-child selector with the even value for the table body rows, but the odd value for the table footer rows. Why is this? The first row of our table is the header row, and we’ve applied a strong color to this row. If we’re going to alternate between rows with and without a background, then the first row after the header should have no background. This is why we used the nth-child(even) selector to pick out the table body rows which should receive the background color. By starting our background on the second table body row, we leave the very first row without a background. There are 5 table body rows. So the last table body row will not have a background color. As a result, we need the first table footer row to have a background color in order for our pattern to remain consistent, and this is why we have used the nth-child(odd) selector to identify the footer rows that should receive the background color. In order to create the every-other-row background color effect we’re also going to have to get rid of our rowspan attribute and add td elements using “No Change” as the content where the rowspan element used to be.

table.ex_table_2 caption { font-size: 1.5em; padding: 10px 5px; } .ex_table_2 th, .ex_table_2 td:nth-child(1) { font-size: 1.1em; font-weight: 500; } .ex_table_2 td, .ex_table_2 th { text-align: center; padding: 5px; } .ex_table_2 tfoot tr:nth-child(1n+2) td { font-size: .9em; font-weight: normal; text-align: left; } .ex_table_2 tfoot tr td, .ex_table_2 tbody tr td, .ex_table_2 thead tr th { border: none; } .ex_table_2 tbody tr:nth-child(even) { background-color: #efecca; } .ex_table_2 tfoot tr:nth-child(odd) { background-color: #efecca; } table.ex_table_2 { border: none; } .ex_table_2 thead { background-color: #a7a37e; }

Most Popular Content Management Systems
CMSUsage *Change Since Jan 1Market Share *Change Since Jan 1
Totals33.3%76%
* Usage is percentage of surveyed websites that use the associated CMS. Market Share is the percentage of surveyed websites powered by a CMS that use the associated CMS. For example, 25.8% of all surveyed websites use WordPress, and WordPress commands 59.1% market share of the total CMS market.
The data in this table is provided courtesy of W3Techs and was captured in February 2016. To learn more about this topic visit the overview of content management systems from W3Techs.
WordPress25.8%+0.2%59.1%+0.3%
Joomla2.8%No Change6.4%No Change
Drupal2.2%+0.1%4.9%No Change
Magento1.3%+0.1%2.9%No Change
Blogger1.2%No Change2.7%No Change

Making a Table Responsive

Our data table now looks pretty good as long as you’re using a laptop or desktop computer to view it. However, when viewed with a small device, such as a small tablet or smartphone, our table is nearly unusable. You either have to zoom so far out that you can’t read the content, or you have to pan back and forth to read all of the content. We can write some additional rules that will be implements based on the results of a media query to resize and rearrange our table’s contents based on the size of a device screen size. The technique we’re going to use is explained in detail at CSS Tricks. By resizing the browser window, we can see that the table begins to have issues when the viewport shrinks below around 780 pixels. Here’s the media query we’ll use to set up 780px as our breakpoint.

@media only screen and (max-width: 780px) {   /*CSS styles will be added here*/ } 

Convert Table Elements

First, we need to convert the table elements to block level elements with a line of CSS that looks like this:

table, thead, tbody, tfoot, tr, th, td {   display: block; } 

This will allow us to break the elements out of their standard layout and position them as we wish.

Move the Table Header Off-Screen

We’re going to be adding new labels to our td elements using CSS, but we want to keep the existing headers for accessibility purposes. To do this we’re going to position the header elements offscreen far enough that they won’t be seen, but assistive technologies will still be able to find them. We’re also going to move the Totals row from the table footer offscreen. While this was an interesting row to have, the information it contained is not critical to understanding the contents of the table.

thead tr, tfoot tr:nth-of-type(1) {   position: absolute;   top: -9999px;   left: -9999px;   } 

Convert Each Table Data Entry Into its Own Row

Rather than position our td elements in a row, we now want them to appear stacked on top of each other. By converting the td elements into block level elements above, we’ve already stacked them on top of each other. Now we’ll apply 50% left-hand padding so that the contents begins in the middle of the td element. We’ll also need to add position: relative; to our td elements so that when we use position: absolute; to add new data lables, they will appear relative to the td element.

td {   position: relative;   padding-left: 50%;   } 

Format the Table Footer Comments

We already hid the table footer Totals line, but we kept the attribution and explanatory comments. Since these td elements will be affected by the styles we wrote in the last step, we need to write more specific styles for these elements.

tfoot tr td {   padding-left: 0%;   text-align: left;   } 

These two rules will cause the text in our footer elements to be left-aligned and to take up the full width of the table.

Format and Add New Data Labels

Our old data labels, the table header th elements, are hidden off screen. They’ll be picked up by assistive technologies, but for most visitors they are not visible. We can use CSS to position new data labels next to our table body td elements with the following rules.

td:before {    position: absolute;   top: 5px;   left: 5px;   white-space: nowrap;   text-align: left;   } 

First, we tell the browser to position the :before content in absolute position relative to the td element, but offset from the top and left sides by 5 pixels. This duplicates the padding added around the content in the td elements. Next, we apply the white-space: nowrap rule to keep the new data labels from wrapping, and align the text with the left-hand side of the td element. Now we’re ready to add our labels.

tbody td:nth-child(1):before { content: "CMS"; } tbody td:nth-child(2):before { content: "Usage*"; } tbody td:nth-child(3):before { content: "+/- since Jan"; } tbody td:nth-child(4):before { content: "Market Share*"; } tbody td:nth-child(5):before { content: "+/- since Jan"; } 

We add tbody to the selector to ensure we don’t accidentally apply labels to the tfoot elements appearing beneath our table caption.

The Finished Product

Once we pull together all of our code, the table code as well as the styling and responsive rules we’ve created, and render our table in a browser, here’s what we get. As you resize your browser window (or if you’re viewing this tutorial on a smartphone) you’ll see that our table automatically reformats once you reach a viewport width of less than 780 pixels, and is now readable on smaller screens.

table.ex_table_3 caption { font-size: 1.5em; padding: 10px 5px; } .ex_table_3 th, .ex_table_3 td:nth-child(1) { font-size: 1.1em; font-weight: 500; } .ex_table_3 td, .ex_table_3 th { text-align: center; padding: 5px; } .ex_table_3 tfoot tr:nth-child(1n+2) td { font-size: .9em; font-weight: normal; text-align: left; } .ex_table_3 tfoot tr td, .ex_table_3 tbody tr td, .ex_table_3 thead tr th { border: none; } .ex_table_3 tbody tr:nth-child(even) { background-color: #efecca; } .ex_table_3 tfoot tr:nth-child(odd) { background-color: #efecca; } table.ex_table_3 { border: none; } .ex_table_3 thead { background-color: #a7a37e; } @media only screen and (max-width: 780px) { .ex_table_3 table, .ex_table_3 thead, .ex_table_3 tbody, .ex_table_3 tfoot, .ex_table_3 tr, .ex_table_3 th, .ex_table_3 td { display: block; } .ex_table_3 thead tr, .ex_table_3 tfoot tr:nth-of-type(1) { position: absolute; top: -9999px; left: -9999px; } .ex_table_3 td { position: relative; padding-left: 50%; } .ex_table_3 tfoot tr td { padding-left: 0%; text-align: left; } .ex_table_3 td:before { position: absolute; top: 5px; left: 5px; white-space: nowrap; text-align: left; } .ex_table_3 tbody td:nth-child(1):before { content: “CMS”; } .ex_table_3 tbody td:nth-child(2):before { content: “Usage*”; } .ex_table_3 tbody td:nth-child(3):before { content: “+/- since Jan”; } .ex_table_3 tbody td:nth-child(4):before { content: “Market Share*”; } .ex_table_3 tbody td:nth-child(5):before { content: “+/- since Jan”; } }

Most Popular Content Management Systems
CMSUsage *Change Since Jan 1Market Share *Change Since Jan 1
Totals33.3%76%
* Usage is percentage of surveyed websites that use the associated CMS. Market Share is the percentage of surveyed websites powered by a CMS that use the associated CMS. For example, 25.8% of all surveyed websites use WordPress, and WordPress commands 59.1% market share of the total CMS market.
The data in this table is provided courtesy of W3Techs and was captured in February 2016. To learn more about this topic visit the overview of content management systems from W3Techs.
WordPress25.8%+0.2%59.1%+0.3%
Joomla2.8%No Change6.4%No Change
Drupal2.2%+0.1%4.9%No Change
Magento1.3%+0.1%2.9%No Change
Blogger1.2%No Change2.7%No Change
Jon is a freelance writer, travel enthusiast, husband and father. He writes about web technologies such as WordPress, HTML, and CSS.