Building Responsive Email Templates with Ink

Ink is a responsive HTML email framework by Zurb – the very awesome team that built Foundation. Ink tries to make it easy to build custom and responsive HTML emails that work on all devices.

This article will take you through the fundamentals of Zurb’s Ink platform as well as covering some best practice email things. We’ll also build a large boilerplate to copy and paste code from. Be sure to check out the demo links or GitHub.

The sad truth about email

frankenemail

If you’ve never had the pleasure of building a custom HTML email template before, let me try to explain what it’s like.

Imagine you were tasked with building a website. This website needs to work in Internet Explorer 6, 7, and 8. On top of that, each version has 10 other versions like it, but they are not quite the same. All of them have their own special quirks and rules. On top of this, you don’t have a nice Chrome Inspector or Firebug tool to debug with. Oh, and then you somehow have to figure how to make it responsive and use new cool tools.

It’s like building a website for 50 different Internet Explorers, blindfolded.

A lot of good front-end developers will refuse to do it. In a lot of cases, it’s assigned to junior devs to basically burn inexpensive hours on until the templates are hacked into completion. If you’re that poor soul, take a deep breath and relax, Ink has already fought this battle for you. This article will take you through core concepts of using Ink to successfully build cross-device and responsive custom HTML email templates.

Step 1: Sync up with your designers

This is an important step that’s not really part of the Official Ink Documentation. With all the cool new features of CSS3, designers can get away with pushing the boundaries of the web. Unfortunately with HTML emails, that’s not the case at all.

Container size

mobile-desktop

Zurb Ink has a fixed max-width of 580px for content. This size is optimal for all devices. This is done with “containers” (similar to Bootstrap and Foundation).

For devices and screen sizes of 600px and below, the containers will fill 95% of the screen’s width to prevent bleeding over a screen’s edge.

Responsive sizes

Zurb Ink has only two media query break points – Desktop and Mobile. Mobile begins when the container is equal or less than 600px (when the container switches from a fixed width to a percentage width).

If a designer is creating mobile templates as well, this doesn’t mean they should build templates for 600px wide. They should be building for the minimum sizes first (mobile-first approach).

This will help prevent things like this from happening:

Screen Shot 2015-04-30 at 8.01.22 AM

I recommend having them build the mobile PSDs with a width of 320px to make sure they look best on iPhones and other small devices.

Custom font’s won’t always work

Using custom fonts will work real nice on a lot of new email devices, but, unfortunately, a lot of legacy email clients won’t load these fonts. There’s no work-around for this either.

For typography, Ink uses this as their base:


    body, table.body, h1, h2, h3, h4, h5, h6, p, td {
        font-family: "Helvetica", "Arial", sans-serif; 
    }

You can use your own websafe fonts as a base, but it’s important to note that not all web safe fonts will work either. MailChimp has an excellent design reference for typography.

So in summary, you can use custom fonts, but expect a fallback to be used for a lot of devices. We’ll cover how to add custom fonts later in this article.

Simple stacking for the responsive grid

When Ink’s grid stacks while switching from desktop to mobile, it’s going to do so in a normal floating order. In Bootstrap and Foundation, you can reverse that stacking order. Unfortunately, since Ink’s grid system has no choice but to be built in tables, it’s not really possible to do that without extra markup.

Key concepts

Firstly, Ink’s Official Documentation is amazing. It covers everything in detail and more. I highly recommend spending an hour and reading it through. We’ll cover mostly everything in the docs and then some other helpful tips.

Assume nothing works

Email clients aren’t browsers. A lot of them only support the bare minimum of what’s required for HTML and CSS. On top of likely being buggy or incomplete, for security and other reasons, they strip out a lot of things.

So there’s things you’ll want to just completely avoid for maximum cross-client support (some more obvious than others):

  • JavaScript
  • Iframes
  • Non-inline styles
  • The <div> tag to manage layout
  • Forms

Inline everything

In order to get your styles to work on all clients, you’ll need to inline your styles. This doesn’t mean you have to do it during development, but before sending out the email you’ll need to do this.

Fortunately, nobody does this by hand. There are plenty of resources to do this for you. On top of this, email services like MailChimp, Campaign Monitor, Mandrill, etc. usually have a service to do this for you. If it doesn’t, you can use this inliner by Zurb to automatically do it:

Use tables for building the layout

Everyone hates this now-a-days, but it’s a must for email clients. You should build your layouts with HTML Tables. This means a few things:

  • The <div> tag won’t work and will likely be stripped out
  • Assume position: absolute; won’t work
  • Doing display: block; on a table probably won’t work
  • Using display: inline-block; won’t be consistent across clients

If you follow Ink’s grid systems detailed below, you shouldn’t have to think about this all too much though.

Specify all image sizes

This is extremely important. You should specify all image sizes. For example:


    <img src="http://placehold.it/400x400.gif/ff2f2f/&text=scotch.io" width="400" height="400">

Ink has a reset on all images to ensure that their max-width never exceeds 100% (aka responsive images). Outlook doesn’t care though. If you don’t specify a size on an image, Outlook will be a mangled mess of overflowed craziness.

If you want to support Retina images, you can just add an image that is twice the size of the specified image.

Here’s an example:


    <img src="http://placehold.it/800x800.gif/ff2f2f/&text=scotch.io" width="400" height="400">

Use absolute URLs

For referencing anything (images, links, etc.), you should always use an absolute URL. This might be more obvious to some, but it’s definitely worth noting.

Sublime snippets

Screen Shot 2015-04-29 at 2.08.17 PM

If you’re developing with Sublime, there’s a nice Sublime Text 2 and 3 package for Zurb Ink snippets. There’s a lot of markup involved for tables and the grid systems Ink provides. I highly recommend checking this out to help save you time.

Remove automatic format detection

I personally love that a lot of clients, especially on mobile, automatically convert dates, phone numbers, and emails to links; however, there’s always that random use case where you might not want to have that happen. Here’s how you can stop it:


    <meta name="format-detection" content="telephone=no">
    <meta name="format-detection" content="telephone=no">
    <meta name="format-detection" content="date=no">
    <meta name="format-detection" content="address=no">
    <meta name="format-detection" content="email=no">

Outlook conditionals

Just like how you would specify Internet Explorer HTML conditional tags, you can do that for Outlook. The only thing that is super weird, you need to match the year to a specific version.

Here’s some sample code snippets:


    <!--[if mso 12]>
        <style type="text/css">
            h1 { color: red; }
        </style>
    <![endif]-->

    <!--[if !mso]><!-- -->
        <h1>Not on Outlook</h1>
    <!--<![endif]-->

Here’s a list matching Outlook version numbers to their year:

  • Outlook 2000 (version 9)
  • Outlook 2002 (version 10)
  • Outlook 2003 (version 11)
  • Outlook 2007 (version 12)
  • Outlook 2010 (version 14)
  • Outlook 2013 (version 15)

Finally, Outlook wraps the entire email in a div (even the <html> tag) called:


    .ExternalClass {

    }

You can use this “super parent” class to also make Outlook specific style changes.

Mobile styles and media queries

Mobile styles can be frustrating to implement. As a result of inlining CSS, you need to add the !important declaration to all CSS properties. This makes a lot of sense if you think about it.

For example, say you have:


    @media only screen and (max-width: 600px) {
        p.blue-on-mobile {
            color: blue;
        }
    }


    <p class=".blue-on-mobile" style="color: red;">I'm red, I swear!</p>

If you’re on a device under 600px, the <p> tag will still be red. This is because @media rules can’t be inline styles. So the inline styles take precedence over the normal CSS just like it would on a website. To override the inline styles, you must use the !important tag.

So this example, the <p> tag will now be blue on mobile:


    @media only screen and (max-width: 600px) {
        p.blue-on-mobile {
            color: blue !important;
        }
    }


    <p class=".blue-on-mobile" style="color: red;">I'm red, I swear!</p>

Ink’s process

Ink has five steps to follow to make sure you’re heading in the right direction. Here they are summarized:

  1. Test in Outlook first (If it works in the Outlooks, it probably works everywhere else)
  2. Add your responsive styles right above the closing </head> tag
  3. Bring your styles inline
  4. Test your email with Litmus
  5. Pray for hotness and send it out

Testing and debugging

litmuslogo

Everyone will have their own method for this. I recommend building the emails in Chrome as you normally would with any other basic HTML page. This way you can visualize the desktop and mobile stuff as your building it out. You’ll also be able to use the inspector to get things buttoned-up.

To debug, you should definitely be using Litmus. I can’t imagine taking an email project on without it. They have this testing service that will actually take a screenshot in every type of client possible. This is great for testing the Outlooks as well as mobile devices.

Screen Shot 2015-04-30 at 9.15.35 AM

The screenshots are even shareable so you can get approval from your manager or the client in case there’s any discrepancies.

Boilerplate

This is Ink’s official starter kit for building HTML email templates:


    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <meta name="viewport" content="width=device-width"/>

            <!-- Framework: ink.css -->
            <style type="text/css">
                #outlook a{padding:0}body{width:100%!important;min-width:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}.ExternalClass{width:100%}.ExternalClass,.ExternalClass div,.ExternalClass font,.ExternalClass p,.ExternalClass span,.ExternalClass td{line-height:100%}#backgroundTable{margin:0;padding:0;width:100%!important;line-height:100%!important}img{outline:0;text-decoration:none;-ms-interpolation-mode:bicubic;width:auto;max-width:100%;float:left;clear:both;display:block}center{width:100%;min-width:580px}a img{border:none}table{border-spacing:0;border-collapse:collapse}td{word-break:break-word;-webkit-hyphens:none;-moz-hyphens:none;hyphens:none;border-collapse:collapse!important}table,td,tr{padding:0;vertical-align:top;text-align:left}hr{color:#d9d9d9;background-color:#d9d9d9;height:1px;border:none}table.body{height:100%;width:100%}table.container{width:580px;margin:0 auto;text-align:inherit}table.row{padding:0;width:100%;position:relative}table.container table.row{display:block}td.wrapper{padding:10px 20px 0 0;position:relative}table.column,table.columns{margin:0 auto}table.column td,table.columns td{padding:0 0 10px}table.column td.sub-column,table.column td.sub-columns,table.columns td.sub-column,table.columns td.sub-columns{padding-right:10px}td.sub-column,td.sub-columns{min-width:0}table.container td.last,table.row td.last{padding-right:0}table.one{width:30px}table.two{width:80px}table.three{width:130px}table.four{width:180px}table.five{width:230px}table.six{width:280px}table.seven{width:330px}table.eight{width:380px}table.nine{width:430px}table.ten{width:480px}table.eleven{width:530px}table.twelve{width:580px}table.one center{min-width:30px}table.two center{min-width:80px}table.three center{min-width:130px}table.four center{min-width:180px}table.five center{min-width:230px}table.six center{min-width:280px}table.seven center{min-width:330px}table.eight center{min-width:380px}table.nine center{min-width:430px}table.ten center{min-width:480px}table.eleven center{min-width:530px}table.twelve center{min-width:580px}table.one .panel center{min-width:10px}table.two .panel center{min-width:60px}table.three .panel center{min-width:110px}table.four .panel center{min-width:160px}table.five .panel center{min-width:210px}table.six .panel center{min-width:260px}table.seven .panel center{min-width:310px}table.eight .panel center{min-width:360px}table.nine .panel center{min-width:410px}table.ten .panel center{min-width:460px}table.eleven .panel center{min-width:510px}table.twelve .panel center{min-width:560px}.body .column td.one,.body .columns td.one{width:8.333333%}.body .column td.two,.body .columns td.two{width:16.666666%}.body .column td.three,.body .columns td.three{width:25%}.body .column td.four,.body .columns td.four{width:33.333333%}.body .column td.five,.body .columns td.five{width:41.666666%}.body .column td.six,.body .columns td.six{width:50%}.body .column td.seven,.body .columns td.seven{width:58.333333%}.body .column td.eight,.body .columns td.eight{width:66.666666%}.body .column td.nine,.body .columns td.nine{width:75%}.body .column td.ten,.body .columns td.ten{width:83.333333%}.body .column td.eleven,.body .columns td.eleven{width:91.666666%}.body .column td.twelve,.body .columns td.twelve{width:100%}td.offset-by-one{padding-left:50px}td.offset-by-two{padding-left:100px}td.offset-by-three{padding-left:150px}td.offset-by-four{padding-left:200px}td.offset-by-five{padding-left:250px}td.offset-by-six{padding-left:300px}td.offset-by-seven{padding-left:350px}td.offset-by-eight{padding-left:400px}td.offset-by-nine{padding-left:450px}td.offset-by-ten{padding-left:500px}td.offset-by-eleven{padding-left:550px}td.expander{visibility:hidden;width:0;padding:0!important}table.column .text-pad,table.columns .text-pad{padding-left:10px;padding-right:10px}table.column .left-text-pad,table.column .text-pad-left,table.columns .left-text-pad,table.columns .text-pad-left{padding-left:10px}table.column .right-text-pad,table.column .text-pad-right,table.columns .right-text-pad,table.columns .text-pad-right{padding-right:10px}.block-grid{width:100%;max-width:580px}.block-grid td{display:inline-block;padding:10px}.two-up td{width:270px}.three-up td{width:173px}.four-up td{width:125px}.five-up td{width:96px}.six-up td{width:76px}.seven-up td{width:62px}.eight-up td{width:52px}h1.center,h2.center,h3.center,h4.center,h5.center,h6.center,p.center,table.center,td.center{text-align:center}span.center{display:block;width:100%;text-align:center}img.center{margin:0 auto;float:none}.hide-for-desktop,.show-for-small{display:none;width:0;mso-hide:all;overflow:hidden}.hide-for-desktop *,.show-for-small *{mso-hide:all}body,h1,h2,h3,h4,h5,h6,p,table.body,td{color:#222;font-family:Helvetica,Arial,sans-serif;font-weight:400;padding:0;margin:0;text-align:left;line-height:1.3}h1,h2,h3,h4,h5,h6{word-break:normal}h1{font-size:40px}h2{font-size:36px}h3{font-size:32px}h4{font-size:28px}h5{font-size:24px}h6{font-size:20px}body,p,table.body,td{font-size:14px;line-height:19px}p.lead,p.lede,p.leed{font-size:18px;line-height:21px}p{margin-bottom:10px}small{font-size:10px}a{color:#2ba6cb;text-decoration:none}a:active,a:hover{color:#2795b6!important}a:visited{color:#2ba6cb!important}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:#2ba6cb}h1 a:active,h1 a:visited,h2 a:active,h2 a:visited,h3 a:active,h3 a:visited,h4 a:active,h4 a:visited,h5 a:active,h5 a:visited,h6 a:active,h6 a:visited{color:#2ba6cb!important}.panel{background:#f2f2f2;border:1px solid #d9d9d9;padding:10px!important}.sub-grid table{width:100%}.sub-grid td.sub-columns{padding-bottom:0}table.button,table.large-button,table.medium-button,table.small-button,table.tiny-button{width:100%;overflow:hidden}table.button td,table.large-button td,table.medium-button td,table.small-button td,table.tiny-button td{display:block;width:auto!important;text-align:center;background:#2ba6cb;border:1px solid #2284a1;color:#fff;padding:8px 0;line-height:initial!important}table.tiny-button td{padding:5px 0}table.small-button td{padding:8px 0}table.medium-button td{padding:12px 0}table.large-button td{padding:21px 0}table.button td a,table.large-button td a,table.medium-button td a,table.small-button td a,table.tiny-button td a{font-weight:700;text-decoration:none;font-family:Helvetica,Arial,sans-serif;color:#fff;font-size:16px;display:block;height:100%;width:100%}table.tiny-button td a{font-size:12px;font-weight:400}table.small-button td a{font-size:16px}table.medium-button td a{font-size:20px}table.large-button td a{font-size:24px}table.button:active td,table.button:hover td,table.button:visited td{background:#2795b6!important}table.button:active td a,table.button:hover td a,table.button:visited td a{color:#fff!important}table.button:hover td,table.large-button:hover td,table.medium-button:hover td,table.small-button:hover td,table.tiny-button:hover td{background:#2795b6!important}table.button td a:visited,table.button:active td a,table.button:hover td a,table.large-button td a:visited,table.large-button:active td a,table.large-button:hover td a,table.medium-button td a:visited,table.medium-button:active td a,table.medium-button:hover td a,table.small-button td a:visited,table.small-button:active td a,table.small-button:hover td a,table.tiny-button td a:visited,table.tiny-button:active td a,table.tiny-button:hover td a{color:#fff!important}table.secondary td{background:#e9e9e9;border-color:#d0d0d0;color:#555}table.secondary td a{color:#555}table.secondary:hover td{background:#d0d0d0!important;color:#555}table.secondary td a:visited,table.secondary:active td a,table.secondary:hover td a{color:#555!important}table.success td{background:#5da423;border-color:#457a1a}table.success:hover td{background:#457a1a!important}table.alert td{background:#c60f13;border-color:#970b0e}table.alert:hover td{background:#970b0e!important}table.radius td{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}table.round td{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}body.outlook p{display:inline!important}@media only screen and (max-width:600px){table[class=body] img{max-width:auto!important;max-height:auto!important}table[class=body] center{min-width:0!important}table[class=body] .container{width:95%!important}table[class=body] .row{width:100%!important;display:block!important}table[class=body] .wrapper{display:block!important;padding-right:0!important}table[class=body] .column,table[class=body] .columns{table-layout:fixed!important;float:none!important;width:100%!important;padding-right:0!important;padding-left:0!important;display:block!important}table[class=body] .wrapper.first .column,table[class=body] .wrapper.first .columns{display:table!important}table[class=body] table.column td,table[class=body] table.columns td{width:100%!important}table[class=body] .column td.one,table[class=body] .columns td.one{width:8.333333%!important}table[class=body] .column td.two,table[class=body] .columns td.two{width:16.666666%!important}table[class=body] .column td.three,table[class=body] .columns td.three{width:25%!important}table[class=body] .column td.four,table[class=body] .columns td.four{width:33.333333%!important}table[class=body] .column td.five,table[class=body] .columns td.five{width:41.666666%!important}table[class=body] .column td.six,table[class=body] .columns td.six{width:50%!important}table[class=body] .column td.seven,table[class=body] .columns td.seven{width:58.333333%!important}table[class=body] .column td.eight,table[class=body] .columns td.eight{width:66.666666%!important}table[class=body] .column td.nine,table[class=body] .columns td.nine{width:75%!important}table[class=body] .column td.ten,table[class=body] .columns td.ten{width:83.333333%!important}table[class=body] .column td.eleven,table[class=body] .columns td.eleven{width:91.666666%!important}table[class=body] .column td.twelve,table[class=body] .columns td.twelve{width:100%!important}table[class=body] td.offset-by-eight,table[class=body] td.offset-by-eleven,table[class=body] td.offset-by-five,table[class=body] td.offset-by-four,table[class=body] td.offset-by-nine,table[class=body] td.offset-by-one,table[class=body] td.offset-by-seven,table[class=body] td.offset-by-six,table[class=body] td.offset-by-ten,table[class=body] td.offset-by-three,table[class=body] td.offset-by-two{padding-left:0!important}table[class=body] table.columns td.expander{width:1px!important}table[class=body] .right-text-pad,table[class=body] .text-pad-right{padding-left:10px!important}table[class=body] .left-text-pad,table[class=body] .text-pad-left{padding-right:10px!important}table[class=body] .hide-for-small,table[class=body] .show-for-desktop{display:none!important}table[class=body] .hide-for-desktop,table[class=body] .show-for-small{display:block!important;width:auto!important;overflow:visible!important}}
            </style>

            <!-- Your Custom CSS here -->
            <style type="text/css">

            </style>

            <!-- Your mobile CSS here -->
            <style type="text/css">
                @media only screen and (max-width: 600px) {

                }
            </style>
        </head>
        <body>
            <table class="body">
                <tr>
                    <td class="center" align="center" valign="top">
                        <center>

                            <!-- Email Content -->

                        </center>
                    </td>
                </tr>
            </table>
        </body>
    </html>

Adding custom fonts

To add custom fonts for maximum cross-client support, you should use @import inline.

Following this, you’ll want to specify the font-family more specific then you normally would. You should assume fonts won’t be inherited. On top of that, the Ink framework is very specific on font-familys. Below is an example of how to add custom fonts as well as some simple utility classes for them.


    <style type="text/css">
        
        /**
         *  Name:   Unica One
         *  Code:   font-family: 'Unica One', cursive;
         *  Use:    Headings
         *  Sizes:  400
         */
        /**
         *  Name:   Volkhorn
         *  Code:   font-family: 'Vollkorn', serif;
         *  Use:    body, paragraphs, etc
         *  Sizes:  400, 700
         */
        
        @import url(https://fonts.googleapis.com/css?family=Unica+One|Vollkorn:400italic,700italic,400,700);

        body, table.body, p, td, .is-vollkorn {
            font-family: 'Vollkorn', serif;
            font-weight: 400;
        }
        h1, h2, h3, h4, h5, h6, .is-unica-one {
            font-family: 'Unica One', cursive;
            font-weight: 400;
        }
      
    </style>

Add a preheader

Screen Shot 2015-04-29 at 3.23.17 PM

Some email clients, like Gmail, will preview the first text that exists after the body tag. This is really great except when your email template has text that isn’t relevant to the content beforehand. The most common hiccup are when templates that have a “View in Browser” button in the header or something.

To guarentee you have a solid text preview, you can add a preheader immediately following the <body> tag. Here’s what it will look like:


    <body>
        <span style="display: none !important;">
            This is my preview text that will show up on email clients!
        </span>
        <table class="body">
            <tr>
                <td class="center" align="center" valign="top">
                    <center>

                        <!-- Email Content -->

                    </center>
                </td>
            </tr>
        </table>

    </body>

Default grid

You’ll probably use the default grid the most. Since the grid is built with tables with cross-client in mind, there’s a ton of markup to do seemingly simple things. At first it might seem exhausting, but it will save you a lot of time in the future if you’re buttoned-up about it.

So let’s break it down. Here it is with fake-markup to help visualize the steps:


    <container>
        <row>
            <wrapper>
                <column class="six">

                    Left content here!

                    <expander></expander>
                </column>
            </wrapper>
            <wrapper class="last">
                <column class="six">

                    Right content here!

                    <expander></expander>
                </column>
            </wrapper>
        </row>
    </container>

Immediately you’ll see that <wrapper> and <column> elements are basically redundant, but necessary when the tables code is added.

The <expander> tag doesn’t have anything in it and is purposefully emtpy. This forces the parent column to go full width on smaller devices. So it’s necessary for the responsive component to stack.

You’ll also notice the class .last is applied to the last wrapper. This is super important to make sure gutters are working correctly with your grid.

Finally, here is that same code with real markup:


    <table class="container">
        <tr>
            <td>
                <table class="row">
                    <tr>
                        <td class="wrapper">
                            <table class="six columns">
                                <tr>
                                    <td>
                                        Left content here!
                                    </td>
                                    <td class="expander"></td>
                                </tr>
                            </table>
                        </td>
                        <td class="wrapper last">
                            <table class="six columns">
                                <tr>
                                    <td>
                                        Right content here!
                                    </td>
                                    <td class="expander"></td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>

It’s a lot of markup. The Sublime Text snippets will save you massive amounts of time.

You can also offset columns by doing .offset-by-{number of columns} on the wrapper class. Here’s an example how:


     <table class="container">
         <tr>
             <td>
                 <table class="row">
                     <tr>
                         <td class="wrapper offset-by-six last">
                             <table class="six columns">
                                 <tr>
                                     <td>
                                         Right content here!
                                     </td>
                                     <td class="expander"></td>
                                 </tr>
                             </table>
                         </td>
                     </tr>
                 </table>
             </td>
         </tr>
     </table>

Sub-Grid (nested columns)

You can also place a columns inside of other columns. This is actually a beautiful thing because sub-grid columns will stack full-width on mobile.

To do this, all you need to do is add a class .sub-columns to the <td> where your content will be going. You’ll also have to add a .last class to the final column.

Here’s a snippet showing how:


    <table class="container">
        <tr>
            <td>
                <table class="row">
                    <tr>
                        <td class="wrapper">
                            <table class="six columns">
                                <tr>
                                    <td class="three sub-columns">

                                        .three.sub-columnds

                                    </td>
                                    <td class="nine sub-columns last">

                                        .nine.sub-columns

                                    </td>
                                    <td class="expander"></td>
                                </tr>
                            </table>
                        </td>
                        <td class="wrapper last">
                            <table class="six columns">
                                <tr>
                                    <td>
                                        Right content here!
                                    </td>
                                    <td class="expander"></td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>

Block-Grid

I really didn’t get the purpose of this at first, but the Block-Grid is actually very useful in some cases. Think of the Block-Grid as a way to do floats in an organized way or something similar to display: inline-block on a bunch of divs.

This definitely has some benefits to it, but it shouldn’t be used as your main templating grid in most cases. You’ll see in their docs and from the demo that the grid doesn’t always line-up.

Here’s a sample of it:


    <table class="container">
        <tr>
            <td>
                <table class="block-grid four-up">
                    <tr>
                        <td>
                            1/4
                        </td><td><!-- Side by side -->
                            2/4
                        </td><td><!-- Side by side -->
                            3/4
                        </td><td><!-- Side by side -->
                            4/4
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>

You’ll notice the side-by-side commented code. You need to eliminate space between the <td> elements because they’re display: inline-block;. This is nothing special to Ink because a row of inline-block elements create spaces between them. Check out Fighting the Space Between Inline Block Elements by Chris Coyier if you’re curious to why this happens.

Full-width rows

Sometimes you’ll want to a full-width row. These are good for your headers and footers, but it can even be used in the main content area if you want.

A quick trick to get these working is to just take the default Grid and simply swap the .row and the .container classes. Here’s an example:


    .full-width-demo {
        background: rgb(25, 229, 144);
    }


    <table class="row full-width-demo">
        <tr>
            <td>
                <table class="container">
                    <tr>
                        <td class="wrapper last">
                            <table class="twelve columns">
                                <tr>
                                    <td>
                                        I'm full width!
                                    </td>
                                    <td class="expander"></td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>

Buttons

Something as seaminly simple as creating a button is quite difficult to support in Outlook. Sizing just doesn’t work well. Fortunately, Ink provides a way to create buttons that not only look in all clients, but they are also responsive.

Here’s some example button code:


    <table class="button success">
        <tr>
            <td>
                <a href="#">Success!</a>
            </td>
        </tr>
    </table>

For sizes, you have the following classes:

  • .tiny-button
  • .small-button or just .button
  • .medium-button
  • .large-button

For colors, you have:

  • .primary
  • .secondary
  • .alert
  • .success

For borders, you have:

  • .radius
  • .round

Make sure the a tag is a block element

The <a> tag in the button by default isn’t display: block; by default. For better usability and easier clicking, you should add that custom style in.


    table.button td a, table.tiny-button td a, table.small-button td a, table.medium-button td a, table.large-button td a {
        display: block !important;
    }

Add a transition to them

Even though most email clients won’t support this, you can add a transition to all buttons with the following code:


    table.button td, table.tiny-button td, table.small-button td, table.medium-button td, table.large-button td {
        -webkit-transition: all 225ms ease;
        -moz-transition: all 225ms ease;
        transition: all 225ms ease;
    }

Custom button colors

You can extend the main .button class to create custom button colors. Here’s styles for Facebook, Twitter, and a Forward button:


    table.facebook td {
        background: #3971B6;
        border-color: #134b90;
    }
    table.facebook:hover td {
        background: #134b90 !important;
    }
    table.twitter td {
        background: #A0D6E2;
        border-color: #7ab0bc;
    }
    table.twitter:hover td {
        background: #7ab0bc !important;
    }
    table.forward td {
        background: #3D3D3A;
        border-color: #333;
    }
    table.forward:hover td {
        background: #111 !important;
    }

Miscellaneous things

Visibility classes

Ink provides visibility classes for hiding and showing things on mobile. Here they are:


    <p class="hide-for-small">Desktop Only</p>
    <p class="show-for-small">Mobile Only</p>

Unfortunately, Outlook won’t support these classes at all. So if you want to support Outlook, you’ll have to use Conditional comments with utitlity classes. This seems crazy, but this is what you have to do:


    <!--[if !mso]><!-- -->
    <p class="show-for-small">Mobile Only</p>
    <!--<![endif]-->

    <!--[if mso]><!-- -->
    <p class="hide-for-small">Desktop only</p>
    <!--<![endif]-->

Centering content

To center content that is both displayed: inline or block, you should follow these three steps:

  1. Add a class .center to the parent
  2. Add a <center> tag around the element
  3. Add a class of .center to the element you want to center

Here’s some example code:


    <td class="center">
        <center>
            <img class="center" src="http://placehold.it/500x500" width="250" height="250">
            <p class="center">I'm centered text</p>
        </center>
    </td>

Panels

Panels don’t really do much, and I think they are quick to confuse some. They’re not some extra functionality as much as a simple style utitlity class.

Hopefully you’re noticing by now that all your content, regardless of the grid choice, will go inside of the final <td> tag. This is always the case with Tables and with Ink.

So, Panels in Ink is simply adding the class .panel to that final td to get some default styles. This is good for protyping and visualizing the grid, but it’s not a special componenet or anything.

Conclusion

That covers almost everything there is about Zurb Ink, responsive emails, and then some. Zurb Ink has been around for about 2 years now. Hopefully this guide will still prove useful to people who are just now diving into the framework.

Make sure you check out our demo and GitHub page for this tutorial!

If you have any questions or need support, feel free to make a comment – or even better, ping us in the forums. I’m pretty well versed with this now and should be able to help debug any issues or questions you have.

I’ll end this with some links to awesome resources: