Build interactive emails with CSS

Oliver Lindberg
net magazine
Published in
8 min readNov 29, 2016


Mark Robbins shows you how to create JavaScript-like functionality in HTML email campaigns with just CSS

‘Email code is so outdated you have to code like it’s 1998.’ That’s a sentiment I hear a lot from web developers, and to some extent it’s true. The latest versions of Outlook desktop still use Microsoft Word to render the HTML, so you’re stuck with building retro, table-based layouts. The Gmail app strips style blocks and linked style sheets so you have to style everything inline.

However, there has been a significant growth in mobile usage over the last few years, and with that a huge percentage of email is being opened on more advanced WebKit-based email apps with great HTML5 and CSS3 support. Yes, we still need tables and inline CSS for the lesser clients, but now we can progressively enhance emails into fully functional interactive microsites.

Interactive email

So what is an interactive email? There are a few definitions flying around at the moment and this is mine: an action taken in an email that triggers an event within the same email.

These ‘actions’ take the form of CSS pseudoclasses :hover, :active, :focus and :checked. The first three are probably more common in web design and I would call these fleeting interactions, as the statement is only true for as long as the action is performed. :checked is a more permanent interaction. Almost like an on/off button, the statement is true until you specifically click to change it.

Show or hide content

If we skip over things like :hover states, the most basic example of these actions is the checkbox hack. Here’s a quick show/hide content example:

input:checked ~ .show{
input:checked ~ .hide,
input:checked ~ .content{
<input type=”checkbox”>
<div class=”show”>show</div>
<div class=”hide”>hide</div>
<label class=”content”>…</label>

When the input is checked, the ‘show’ button is hidden and the ‘hide’ button and content are displayed. Notice the content is wrapped in its own label. This overrides the function of the parent label, so clicking in this area won’t alter the checkbox. This technique is also often used for expanding hamburger menus in email.

Image gallery

To take this a step further, we can swap the checkbox for an array of radio buttons. The advantage here is that only one radio button in an array can have the :checked value at a time. This is great for things like image galleries, as only one image will be displayed at a time.

By simply swapping the images for text and moving the controls so they appear above the content, this technique could also be used for a tabbed layout.

Default template An image gallery powered by radio buttons from the default Rebelmail template

Punched card coding

This next concept goes even further and has a huge scope of use cases. Until now we’ve nested an input inside a label and placed the input as a direct sibling of the content we’re editing. With this new technique we put all the radio buttons and checkboxes at the very top of the email, reference them with an ID on the input and assign a for attribute on labels in the content to activate them. When I first started experimenting with this concept, I had a large number of radio buttons visible at the top of the page and it reminded me of the old IBM punched card computers, hence the name I’ve coined: punched card coding.

The function of the inputs can be viewed in a similar way too. The card has a number of places where it can be punched or not, the same way the inputs can be :checked or not. This could also be seen as a series of true or false statements (or ones and zeros if you want to get all binary about it). These values can now be strung together to form complex logic.

#a2:checked ~
#b4:checked ~
#c9:checked ~
#d1:not(:checked) ~
#e5:checked ~ table{}

Using this technique we can create a fully functional shopping cart in a single email. In this email you can adjust the quantity of each item or remove it from the cart completely. This in turn affects the line price, subtotal, tax, discount and total price, which are all calculated using a series of CSS counters.

#item1-quantity3:checked {
counter-increment:price-with-tax 18270 discount
1827 price 17400 tax 870 item-1-line-price 17400;

With this example you can also customise the size and colour of each item on a separate page. The pages are wrapped in a div that will only show when the corresponding radio button is :checked. It’s not dissimilar to our gallery example.

The user’s card details (last four digits only) and delivery addresses are also pulled into the template. Then the selected card, delivery address and all the shopping cart options are submitted to a server that will process the order.

Slack apps Multiple arrays of radio buttons alongside an IBM punched card


Games are another great use case. Allowing the user to earn a reward created a sense of achievement, and users are much more engaged than they would be with an email offering an arbitrary discount. One of the first interactive emails I built was the ThWack-A-Vole game.

At the very core it’s simple: click three times to score three points and win a prize. To turn this into a game, I just added CSS animation to make the labels harder to click.

Get Involved Game-based emails engage users and create a sense of achievement

Bugs and complexities

So far everything is sounding great, but anyone who has worked on HTML email will know it’s never that simple. So at the risk of talking you out of it, here are some of the complexities to consider.


PC desktop versions of Outlook still use MS Word to render HTML. This means none of what I’ve talked about will work; even something as simple as an animated GIF will only load the first frame. The good news is Outlook only accounts for about 7 per cent of email opens (statistics in this section
come from, based on 1.31 billion opens in March 2016).

This means progressive enhancement is key to building a successful interactive campaign. To help with this we’ve created three categories of interactive support:

  • Interactive: These are WebKit-based email clients with good support for all the examples mentioned, (about 60 per cent of opens)
  • Limited: Generally these don’t support the for tag on labels, so we lose more advanced interactions but can still do things like galleries, tabs and hamburger menus (around 20 per cent)
  • Static: Similar to any standard email campaign you’re used to seeing (around 20 per cent)
Payment You can only select cards and addresses already registered in the user’s account on the web


All this complexity obviously means more time. Just like complicated websites, interactive emails take longer to build. However, the testing process also becomes far more complex.

Any web developer will tell you that Chrome, Firefox, Safari, Opera, Edge and so on can render things differently, so now consider testing Gmail in each of those, then Yahoo, then AOL Mail. Now look at mobile browsers; each of those has an iOS and Android app, not to mention the native email apps phone manufacturers add and the huge number of third party apps.

Screenshot aggregation tools like Litmus and Email on Acid can help. These work by sending your email to around 40 email clients and returning screenshots of each. However, this only really helps with basic layout testing. Interactive testing can’t be done with screenshots; you need real devices and that means putting together a device lab.

Product page This product page from a multi-page shopping cart email can be accessed without leaving the email


Unlike web browsers, email clients don’t have public beta versions for developers to test on. They don’t have release notes saying what changes they’ve just made or that are upcoming. And when a campaign is sent there’s very little you can do to update it (adding an external style sheet with a zero cache is one option here).

This has lead to a very strong community of sharing. Every new update, bug and fix can be found very quickly on the Litmus community forum or the Twitter hashtag #emailgeeks.


Email service providers are well known for editing code before sending. They know things like interactivity and animation aren’t supported in every client so they’ll be stripped, CSS may automatically be inlined, doctypes may be changed. Some even add additional code increasing your file size. As a result, it’s always worth sending your tests in exactly the same manner that you’ll send your campaigns.

File size

There is a generally accepted size limit of 102kb for your HTML file (not including images). Over this, several email clients will clip the code, which will lead to a number of issues, such as unclosed tags. Also you’re more likely to end up in a spam filter. At the top of the page is an example of an otherwise very good interactive email that came to my Gmail account. The issue here is the interactive code was placed before the fallback, so when the code was clipped the fallback was removed and the interactive code was hidden by default.

Order matters Gmail will clip your code after 102KB, so make sure you put your fallback code first

In conclusion

Email is an old technology, but that doesn’t mean it’s outdated. Innovation can and should take place in whichever field you choose. Many people write off email development due to what they perceive are its limitations, but the biggest limitations are often those in your head. And that’s why I love it.

In many ways email development is the frontier; it’s the Wild West. Modern web development is about following the rules and writing clean code; modern email development is about breaking rules then patching them back together with gaffer tape and superglue.

Mark is a senior email architect at Rebelmail and changing the way people think of email. You can often find him discussing the quirks of email rendering on Twitter @M_J_Robbins and as a moderator at the Litmus Community.

This article originally appeared in issue 281 of net magazine



Oliver Lindberg
net magazine

Independent editor and content consultant. Founder and captain of @pixelpioneers. Co-founder and curator of GenerateConf. Former editor of @netmag.

Recommended from Medium


See more recommendations