Monday, April 4, 2016

An Even Better Credit Card

One of my most popular entries on this blog is the inline credit card entry form highlighted in A Better Credit Card.

While that overall design is efficient, it does not necessarily reduce the cognitive load of a page, and cognitive load is often a significant factor in conversion and general usability. After writing about using CSS transform to flip an image, I decided to revisit the card entry form to consider how it might be modified to reduce cognitive load. In the end, I decided to use a skeuomorphic pattern and build a prototype for card entry (which you can see in my prototype collection).

One word of warning before we begin: elements are positioned, shown, and hidden using CSS, but there is no way to modify the class attribute without using JavaScript. I am advising, therefore, that even though the markup can be used as-is, the CSS be initially applied using JavaScript. This step is not done in the prototype.

Here's how the prototype was built...

First, as I always do, I started with the markup. Since I'm using a skeuomorphic design pattern, my card entry form uses the card type, the account number, the customer's name, the CSC (or, as we say in the US, the CVV), and the expiration date and skips other inputs, like a starting date (does anyone even have a Switch or Solo card anymore?). Although it's not purely semantic, I did add a visual element for the mag stripe on the back of the card.

HTML
<form id="card_entry">   <div class="card" id="card">     <p class="magstripe" aria-hidden="true"> </p>     <fieldset class="card-type" id="card-type">       <legend>Card Type</legend>       <span class="card-icon">         <input id="amex" name="card_type" type="radio" value="amex">         <label class="card-type-label" for="amex">American Express</label>       </span>       <span class="card-icon">         <input id="visa" name="card_type" type="radio" value="visa">         <label class="card-type-label" for="visa">Visa</label>       </span>       <span class="card-icon">         <input id="mastercard" name="card_type" type="radio" value="mastercard">         <label class="card-type-label" for="mastercard">Mastercard</label>       </span>     </fieldset>     <p class="acct">       <label for="acct">Account number</label>       <input id="acct" name="acct" type="text" value="4123 4567 8901 2349">     </p>     <p class="name">       <label for="fn">Name on Card</label>       <input id="fn" name="fn" type="text" value="jane doe">     </p>     <fieldset class="expiry">       <legend>Good Thru</legend>       <p class="date">         <label for="expiry_mo">Expiration Month</label>         <input class="mo" id="expiry_mo" name="expiry_mo" type="text" value="12">         <span class="separator" aria-hidden="true">/</span>         <label for="expiry_yr">Expiration Year</label>         <input class="yr" id="expiry_yr" name="expiry_yr" type="text" value="25">       </p>     </fieldset>     <p class="security-line">       <span class="signature" aria-hidden="true">Your signature</span>       <label for="cvv">CVV</label>       <input class="cvv" id="cvv" name="cvv" type="text" value="123">     </p>   </div>   <button id="cardflip" aria-hidden="true" style="margin:1em;" type="button">?</button> </form>


Note
Although you will often need to collect an address along with card information, it will be to your advantage to create an address collection form component, because the format for each country is specific and creating a component - even a component for each country - will mean you won't have to repeat that work. Credit and debit cards, on the other hand, generally follow a single form regardless of country.

As you'll notice, the markup follows accessibility guidelines. Each INPUT has an associated label, there is a LEGEND tag for each FIELDSET element, and elements that are purely visual are hidden using aria-hidden. This is very important and is one of the ways we make sure the markup is semantic. To ensure the accessiblity features don't interrupt the visual representation, breaking our skeuomorphic pattern, I'm using absolute positioning with a clipped rectangle (which has proven to be the approach most recognized by assistive technology) to hide elements not visibly present on a physical card.

The meat in this dish is the CSS (rather than give a complete code listing here, I'm going to link to the stylesheet). The stylesheet not only positions the account number, name, CSC, and expiration date, it will either invert the card and display the CSC entry field (for any card not an American Express) or display the CSC entry field on the front of the card (for an American Express card).

CSS
.card {   background-size:cover;   background:rgba(100, 160, 200, 1) url("blank_card.jpg");   border-radius:10px;   border:1px solid rgba(170, 170, 170, 1);   font-family:monospace;   font-size:12px;   font-weight:800;   height:14em;   line-height:12px;   margin:0;   overflow:hidden;   padding:1em 0;   transition:transform 1s;   width:25.5em; } .card.invert {   background:rgba(100, 160, 200, 1);   -ms-transform:rotateX(0deg) rotateY(180deg);   -webkit-transform:rotateX(0deg) rotateY(180deg);   transform:rotateX(0deg) rotateY(180deg); }


By placing the transform rule on the card (CSS lines 17-22), the account number, name, and expiration date are all rotated as a single unit, leaving the matter of shifting the text-shadow and color to make the text appear inset rather than outset (since the name and account number are embossed on the card). All that remains after changing the text effect is hiding or revealing elements that are printed (not embossed), only appear on the front or back of the card - the expiration date label and magstripe, for example. Creating a 1 second transition effect for the transform (CSS line 14) animates the flip, reducing (or eliminating) the cognitive load associated with the interface change.

Note
To address the slight differences in Internet Explorer, there is an IE 9 stylesheet included in the prototype using a conditional comment and CSS rules (at the end of the card.css stylesheet) that look for IE 10 or IE 11 in the data-useragent attribute of the HTML. You can add the data-useragent to the HTML element by adding the following to your document head: <script>document.documentElement.setAttribute('data-useragent', navigator.userAgent);</script>


The prototype also includes some vanilla JavaScript that will change the class attribute of the card type input when the card type RADIO input is checked (using the onchange event) and will change the class attribute of the DIV card element to flip the card. Generally, if the user shifts focus to the CSC, we check to verify that we should invert the card (that the card is not an American Express). All other inputs are on the 'front' of the card so if focus moves to any other input, we remove the 'invert' class and show the front. The JavaScript provided as part of the prototype should not be used as anything other than a general guideline of how the interface should behave - it does not follow best practices because it is intended to be thrown away and is in its most basic, generally understandable form. Note: the JavaScript for this prototype will likely be modified in the future to enhance the prototype.

Note
The prototype also has a button that will flip the card so it's a little more mobile-friendly, specifically for devices that don't have a 'next field' button when entering data into forms. This button (HTML line 43) is separate from the card DIV but is placed close to the card so its meaning is a little clearer.


That's pretty much all there is to it - a skeuomorphic credit card entry form that will reduce cognitive load. There will be users who are more comfortable using it than the quicker inline form...but remember, you need to A/B test any changes to your user interface to figure out which is better for your users.

Happy coding.

No comments:

Post a Comment