Our most recent newsletter was all about email accessibility, and a key goal for us was to include fantastic Paul Airy’s Accessibility Switcher™ to allow our subscribers to change the font size and adapt the contrast of our newsletter.

Check out the email here.

To seamlessly integrate the Accessibility Switcher™ into Litmus’ newsletter design, we adapted Paul’s original technique a bit here and there. Here’s a detailed walk-through of what we were trying to achieve and how we brought the Accessibility Switcher™ to live in our newsletter:

We wanted to bring it into our standard newsletter design instead of having it live outside of the document flow.

Because the Accessibility Switcher™ uses the punched-card coding method of creating interactive email, the usage of CSS sibling combinators meant that the code (in this case, a <div class="main-wrapper"> that contains all of the affected sections) being changed by the switcher must be placed after the switcher code in order for it to work.

In Paul’s original switcher, this is solved by having the buttons live at the very start of the HTML body, with a fixed position at the top left corner of the design. That way, the <div class="main-wrapper"> basically contains everything that comes after. However, we at Litmus wanted to feature the switcher buttons nested within the hero module of our newsletter template to bring more attention to them—but that meant that the switcher had to be placed after our header bar, and we wanted the parent wrapper that contained the switcher buttons to change as well.

So how do we solve this? First, I separated the <input> and <label> code. The <input> is what really controls the interactive action behind the scenes, and the <label> is just the visual aspect, and there was no real reason they had to stay together. That way, I could place the <label> inside of our hero module, and the hidden <input> code could still live at the very beginning of the email.

Before:

    <!--[if (gte mso 9)|(IE)]>
    <table class="hideFromOutlook" cellpadding="0" cellspacing="0" border="0">
        <tr>
            <td>
    <![endif]-->

    <input id="standard-layout" class="standard-layout" type="radio" name="layout" checked style="position:absolute;visibility:hidden;display:none !important;" >
    <label for="standard-layout" class="layout-buttons settings-box-element"></label>
    <input id="large-layout" class="large-layout" type="radio" name="layout" style="position:absolute;visibility:hidden;display:none !important;" >
    <label for="large-layout" class="layout-buttons settings-box-element"></label>
    <input id="contrast-layout" class="contrast-layout" type="radio" name="layout" style="position:absolute;visibility:hidden;display:none !important;" >
    <label for="contrast-layout" class="layout-buttons settings-box-element"></label>
    <!--[if (gte mso 9)|(IE)]>
                </td>
            </tr>
        </table>
    <![endif]-->

    <div class="main-wrapper"></div>

After:

    <input id="standard-layout" class="standard-layout" type="radio" name="layout" checked style="position:absolute;visibility:hidden;display:none;" >
    <input id="large-layout" class="large-layout" type="radio" name="layout" style="position:absolute;visibility:hidden;display:none;" >
    <input id="contrast-layout" class="contrast-layout" type="radio" name="layout" style="position:absolute;visibility:hidden;display:none;" >

    <div class="main-wrapper">

    <!--[if !mso]><! -->
    <div class="switchtabs" style="width: 500px; max-width: 500px;">
       <label for="standard-layout" class="layout-buttons settings-box-element">
           <span class="label-text">S<br>
          <span class="switch-type">Standard</span>
       </span>
       </label>
        <label for="large-layout" class="layout-buttons settings-box-element">
            <span class="label-text">L<br>
           <span class="switch-type">Large Text</span>
            </span>
        </label>
       <label for="contrast-layout" class="layout-buttons settings-box-element">
           <span class="label-text">C<br>
              <span class="switch-type">Contrast</span>
           </span>
       </label>
    </div>
    <!--<![endif]-->

    </div>

Separating the <input> and <label> code unfortunately broke the label styling, since the original switcher relied on the Adjacent Sibling Combinator to control the look of the checked state of the labels. Instead, I used nth-child selectors and tied the <input>’s :checked state with its matching <label> style.

Before:

    input[type="radio"]:checked + label { color:#ffffff !important; border-color:#e83737 !important; background-color:#e83737 !important; }

After:

    .switchinputs > input:nth-child(1):checked ~ .main-wrapper .switchtabs label:nth-child(1),
    .switchinputs > input:nth-child(2):checked ~ .main-wrapper .switchtabs label:nth-child(2),
    .switchinputs > input:nth-child(3):checked ~ .main-wrapper .switchtabs label:nth-child(3) {
    background-color: #EEB35B !important;
    }
    .switchinputs > input:nth-of-type(3):checked ~ .main-wrapper .switchtabs label:nth-child(3) span {
    color: #08223E !important;
    }

Oh, and I also added hover effects to the label buttons. (Because I love hover effects 😂) The code below ensured that the hovered buttons were highlighted with a light coral background color and dark navy text.

    label:hover { background-color: #F6C6A4 !important; }
    label:hover span { color: #08223E !important; }

We wanted it to work on mobile devices.

Since iPhone & Android native mail apps have robust support for interactive CSS, we wanted to take the opportunity to enable the Accessibility Switcher™ for mobile as well as desktop. All this meant was removing the @media query below:

    @media only screen and (max-device-width:730px), screen and (max-width:730px) {
        .standard-layout + label, .large-layout + label, .contrast-layout + label {display:none !important;}
    }

And taking the Accessibility Switcher™ CSS out of the @media only screen and (min-device-width:769px), screen and (min-width:769px) media query.

We wanted users to know they can interact with the switcher.

Adding a faint CSS animation to the checked label button brought more attention to the fact that this was an actionable element rather than a decorative one.

    @-webkit-keyframes colorani {
      from {background-color: #EEB35B; box-shadow: none;}
      to {background-color: #ffffff; box-shadow: 0 3px 6px 0 rgba(0,0,0,0.2);}
    }

    .switchinputs > input:nth-child(1):checked ~ .main-wrapper .switchtabs label:nth-child(1),
    .switchinputs > input:nth-child(2):checked ~ .main-wrapper .switchtabs label:nth-child(2),
    .switchinputs > input:nth-child(3):checked ~ .main-wrapper .switchtabs label:nth-child(3) {
        background-color: #EEB35B !important;
        animation: colorani 1s infinite alternate ease-in !important;
        -webkit-animation: colorani 1s infinite alternate ease-in !important;
    }

We wanted the fallback version to show up where the Accessibility Switcher™ wasn’t fully supported.

Finally, we wanted to ensure a solid fallback experience for every email client, which meant providing a different hero module with different messaging in case the Accessibility Switcher™ didn’t render correctly—or at all. Even if the button labels rendered, they might not be functional across all webmail clients.

To circumvent this issue, I used the external CSS method for interactive fallbacks as outlined in my blog post here. Basically because the :checked interactive functionality overlaps greatly with Linked CSS support, putting your punched-card interactive CSS in an external CSS file ensures that only email clients that can fully support interactivity will display the interactive version.

Here’s what the fallback version looks like on email clients that can’t support interactivity:

Do you have any questions about our implementation of the Accessibility Switcher™? Let us hear them!

Accessibility Switcher™ © Paul Airy 2019. Used with permission.