Coding mobile-first emails

A practical step-by-step guide

Stig Morten Myre
Campaign Monitor Engineering

--

Update: Since this article was written, Gmail has added support for media queries. However, due to some caveats in their implementation, the following mobile-first technique remains the most reliable for now.

You may have read our announcement on the Campaign Monitor blog that email campaigns created with our Email Builder now render beautifully across all major devices and clients. This includes the Gmail and Yahoo! Mail apps on Android and iOS.

While that post focused on the impact this breakthrough will have on your campaigns and the subscribers who open them, here I want to jump into the nerdy, gritty details of how we achieved it. To recap, the problem we’re tackling is the lack of support in mobile clients for features like media queries, which are needed for the traditional approaches to responsive email.

Typically, emails are coded starting with an old school, table based desktop version, with mobile styles applied through a max-width media query to reflow the tables. In email clients that don’t support this, this approach can result in inconsistent rendering and difficult to read emails.

We’re going to flip the formula and start with the mobile version first instead, then work our way back to the desktop version.

Mobile first

Coding an email that works on mobile is simple. In fact, we’ll do so using only a few <div> elements for the layout:

<div class="wrapper">
<div class="layout">
<div class="spacing">
<p>Herligheter hva penge, tærer innflytelse forderve hukommelse.</p>
<p>Lettsindigheten anstrengende røbe, overser rekk makroner, sengeliggende avbetaler klokt uskjønt fedre.</p>
</div>
</div>
</div>

We’ll give both the email and the layout a background color, and make the layout 320px wide and centered:

body,
.wrapper {
background-color: #add8c7;
}
.layout {
background-color: #ffffff;
Margin: 0 auto;
width: 320px;
}
.spacing {
Margin: 20px;
}
p {
Margin: 20px 0;
}

The inner <div> in the HTML with the “spacing” class is there to add spacing around the text, which is achieved using Margin. This is widely supported when used like this, especially when written with a capital M, which gets us support in the old version of Outlook.com (currently being phased out).

Because of margin collapsing, the top and bottom margins will break out of the parent .layout and its white background color, but we’ll fix that in a bit.

This simple email will render consistently across all common mobile clients, and most desktop and webmail clients too.

A media query for desktop

The plan isn’t just to serve a mobile version on all platforms though. When the email is viewed in an email client with more screen real estate, we want to make use of that with a full desktop version.

Let’s first divide our email content into two columns with another pair of <div>s:

<div class="wrapper">
<div class="layout">
<div class="column narrow">
<div class="spacing">
<p>Herligheter hva penge, tærer innflytelse forderve hukommelse.</p>
</div>
</div>
<div class="column wide">
<div class="spacing">
<p>Lettsindigheten anstrengende røbe, overser rekk makroner, sengeliggende avbetaler klokt uskjønt fedre.</p>
</div>
</div>
</div>
</div>

This gives us some classes to target in our stylesheet, that we’ll use to make these elements display as columns on desktop.

This is where media queries come in. Normally if we were adding mobile styles to a desktop version, we would use a max-width media query, so the mobile styles would only apply up to a certain email client width. But since we’re starting with the mobile version, we’ll use a min-width media query instead, so the desktop version styles kick in when the email is displayed at the minimum width or above:

.layout {
display: table;
}
@media screen and (min-width: 620px) {
.layout {
width: 600px !important;
}
.column {
display: table-cell;
}
.narrow {
width: 200px !important;
}
.wide {
width: 400px !important;
}
}

That’s right — CSS tables! By applying display: table; and display: table-cell; when viewed in larger viewports, the .layout element will behave as though it were a table, and the .column elements will be rendered as its table cells, the left 200px wide, and the right 400px.

We’ve placed display: table; outside the media query so it will be inlined along with the mobile styles. This also fixes the margin collapsing on the .spacing elements.

Without display: table; on .layout in the mobile version, these margins would end up outside the layout and its background color.

The media query and CSS table combination is surprisingly well supported across major email clients. There are a few notable exceptions, including the new version of Outlook.com, the desktop versions of Outlook, and Google’s webmail clients Gmail, Google Apps and Inbox.

We’ll address that next.

*In Outlook 2000–03, media query support depends on which version of Internet Explorer is installed.
**The old Outlook.com displays the desktop version correctly, but the new version doesn’t.

Dummy attribute selectors for the new Outlook.com

At the time of publishing, Outlook.com is running two different webmail clients in parallel: one with media query support and one without.

Unfortunately, the one that does support our min-width media query is in the process of being phased out, as users are being migrated to a newer version based on Office 365/Outlook Web Access. From an email rendering perspective, this is a definite downgrade.

We can workaround this, though. The new Outlook.com has a bug where, if it finds a CSS selector with an attribute selector in it, such as [href] img, discards the attribute selector part of it, and leaves the rest. In the above example, this would leave us with the selector img, which will select all images, not just the ones with a link around them.

This by itself is a bad thing, but it means we can exploit the bug to include a copy of the desktop styles that only Outlook.com will see.

We’ll place a copy of the desktop styles outside the media query, but prefix each rule with a dummy attribute selector like[owa].

[owa] .layout {
width: 600px !important;
}
[owa] .column {
display: table-cell;
}
[owa] .narrow {
width: 200px !important;
}
[owa] .wide {
width: 400px !important;
}

Other email clients will ignore this CSS because there are no elements that match the [owa] selectors, but Outlook.com will apply the desktop styles just like we want.

Let’s cross our fingers that the Outlook.com team fixes media query support before they fix this bug.

A conditional table for Outlook

To place elements beside each other in Outlook, we need to introduce an HTML table. But to prevent it from messing up our mobile version, the table will be hidden inside conditional comments:

<div class="layout">
<!--[if (mso)|(IE)]>
<table class="layout" cellpadding="0" cellspacing="0" align="center" bgcolor="#ffffff">
<tr>
<td class="column" valign="top" style="width: 200px;">
<![endif]-->
<div class="column narrow">
<div class="spacing">
<p>Herligheter hva penge, tærer innflytelse forderve hukommelse.</p>
</div>
</div>
<!--[if (mso)|(IE)]>
</td>
<td class="column" valign="top" style="width: 400px;">
<![endif]-->
<div class="column wide">
<div class="spacing">
<p>Lettsindigheten anstrengende røbe, overser rekk makroner, sengeliggende avbetaler klokt uskjønt fedre.</p>
</div>
</div>
<!--[if (mso)|(IE)]>
</td>
</tr>
</table>
<![endif]-->
</div>

Conditional comments enable us to specifically target Outlook. To other email clients the code looks like regular HTML comments, which are ignored when rendering the email.

The [if (mso)|(IE)] expression means we’re targeting all versions of Microsoft Office, i.e. Outlook 2007/2010/2013/2016 which share their rendering engine with Word, and all versions of Internet Explorer, which is used to render emails in Outlook 2000/2002/2003.

With our two column design propped up by Outlook-only tables, that leaves only Google’s webmail clients: Gmail, Google Apps and Inbox.

Calculations for Google’s webmail trio

These clients don’t give us much to work with. CSS is only supported when coded inline with style attributes. There’s no media query support, and there are no other ways of targeting Google’s webmail clients without also targeting their mobile apps.

Our solution? The calculation feature in CSS.

Instead of setting a CSS property to a fixed number value like 600px, you can set it to a calc() function containing a mathematical expression. In our case, we want the width of our layouts and columns to change depending on the width of the email client.

For our .layout width, we’ll use the following function:

width: calc((Desktop Width - Mobile Width) * 100% - (Desktop Width - Mobile Width) * Breakpoint - Desktop Width);

The layout has a desktop width of 600px and a mobile width of 320px. And we’ll use the same 620px breakpoint as in our media query to switch between the two.

With the numbers filled in, the function looks like this:

width: calc((600px - 320px) * 100% - (600px - 320px) * 620 - 600px);

When the email client executes this function, the 100% is replaced with the email client width.

We can mathematically simplify the function:

width: calc(28000% - 173000px);

When the email client width is exactly 620px, this function returns 600px, which is the desktop width we want. But if the email client width is reduced by just one pixel to 619px, the result is 320px, our mobile width. This allows us to switch successfully between desktop and mobile views on the right screens.

The email client width will rarely be exactly 619px or 620px though. So to limit the range of possible widths to just the two we want, we set 600px as the max-width and 320px as the min-width.

With these inline styles, we can achieve something similar to our media query, without the need for media query support. While calc() isn’t supported everywhere, it does work in all of Google’s email clients, both webmail and mobile.

Because older mobile email client versions don’t support calc() functions, we’ll also keep the pixel based width from before as a fallback.

Here’s how it looks when combined:

.layout {
max-width: 600px;
min-width: 320px;
width: 320px;
width: calc(28000% - 173000px);
}

We’ll do a similar calculation for the columns too, but we’ll base it on the width of .layout since that’s the parent of the .column elements. That means we’ll use the layout’s desktop width of 600px as the breakpoint, so when the layout switches to its desktop width, so will its columns.

The function for the 400px column works the same way as the layout:

width: calc((Desktop Width - Mobile Width) * 100% - (Desktop Width - Mobile Width) * Breakpoint - Desktop Width);width: calc((400px - 320px) * 100% - (400px - 320px) * 600px - 400px);width: calc(8000% - 47600px);

But for the 200px column, which is wider on mobile than on desktop, we need to switch it up slightly:

width: calc(((Mobile Width - Desktop Width) * (Breakpoint - 1px) + Mobile Width) - (Mobile Width - Desktop Width) * 100%);width: calc(((320px - 200px) * (600px - 1px) + 320px) - (320px - 200px) * 100%);width: calc(72200px - 12000%);

We’ll also float the columns to the left, so that they’ll sit beside each other at the desktop width, but stack on mobile when only one column can fit width-wise:

.narrow {
Float: left;
min-width: 200px;
max-width: 320px;
width: 320px;
width: calc(72200px - 12000%);
}
.wide {
Float: left;
min-width: 320px;
max-width: 400px;
width: 320px;
width: calc(8000% - 47600px);
}

And with that, we have a responsive layout that works in all of Google’s clients, as well as all other major clients.

Live demo

💌 Send a demo to your email address

You can also send your own mobile-first emails with our drag-and-drop Email Builder, without ever touching a line of weird calc() code.

Email client support

The email clients we’ve tested show up in Campaign Monitor’s usage stats as having at least 1% of the opens across the billions of emails our customers have sent in the last year.

While this technique will surely break in some of the less capable, lesser used email clients out there, this will typically mean that people opening the email on desktop will see the mobile version. While not ideal, a desktop client displaying the mobile version of an email is a much better reading experience than a mobile client trying to jam the desktop version onto a small screen.

The Space Race

As I was starting to implement this technique in our Email Builder, email developer Rémi Parmentier published a technique very similar to the Gmail part of my solution.

His calculations work for fluid layout widths, which may be a better option depending on the email you’re building. My technique on the other hand is built to switch between two fixed widths for mobile and desktop, which can provide more predictability, especially when working with background images.

Rémi’s post explains his technique really nicely, and is well worth a read.

Thanks for reading!

I’m keen to hear from you if you think of ways to improve on this technique, or if you run into any email clients where it doesn’t hold up well.

Leave a comment or find me on Twitter.

--

--