rowid,title,contents,year,author,author_slug,published,url,topic
181,Working With RGBA Colour,"When Tim and I were discussing the redesign of this site last year, one of the clear goals was to have a graphical style without making the pages heavy with a lot of images. When we launched, a lot of people were surprised that the design wasn’t built with PNGs. Instead we’d used RGBA colour values, which is part of the CSS3 specification.
What is RGBA Colour?
We’re all familiar with specifying colours in CSS using by defining the mix of red, green and blue light required to achieve our tone. This is fine and dandy, but whatever values we specify have one thing in common — the colours are all solid, flat, and well, a bit boring.
Flat RGB colours
CSS3 introduces a couple of new ways to specify colours, and one of those is RGBA. The A stands for Alpha, which refers to the level of opacity of the colour, or to put it another way, the amount of transparency. This means that we can set not only the red, green and blue values, but also control how much of what’s behind the colour shows through. Like with layers in Photoshop.
Don’t We Have Opacity Already?
The ability to set the opacity on a colour differs subtly from setting the opacity on an element using the CSS opacity property. Let’s look at an example.
Here we have an H1 with foreground and background colours set against a page with a patterned background.
Heading with no transparency applied
h1 {
color: rgb(0, 0, 0);
background-color: rgb(255, 255, 255);
}
By setting the CSS opacity property, we can adjust the transparency of the entire element and its contents:
Heading with 50% opacity on the element
h1 {
color: rgb(0, 0, 0);
background-color: rgb(255, 255, 255);
opacity: 0.5;
}
RGBA colour gives us something different – the ability to control the opacity of the individual colours rather than the entire element. So we can set the opacity on just the background:
50% opacity on just the background colour
h1 {
color: rgb(0, 0, 0);
background-color: rgba(255, 255, 255, 0.5);
}
Or leave the background solid and change the opacity on just the text:
50% opacity on just the foreground colour
h1 {
color: rgba(0, 0, 0, 0.5);
background-color: rgb(255, 255, 255);
}
The How-To
You’ll notice that above I’ve been using the rgb() syntax for specifying colours. This is a bit less common than the usual hex codes (like #FFF) but it makes sense when starting to use RGBA. As there’s no way to specify opacity with hex codes, we use rgba() like so:
color: rgba(255, 255, 255, 0.5);
Just like rgb() the first three values are red, green and blue. You can specify these 0-255 or 0%-100%. The fourth value is the opacity level from 0 (completely transparent) to 1 (completely opaque).
You can use this anywhere you’d normally set a colour in CSS — so it’s good for foregrounds and background, borders, outlines and so on. All the transparency effects on this site’s current design are achieved this way.
Supporting All Browsers
Like a lot of the features we’ll be looking at in this year’s 24 ways, RGBA colour is supported by a lot of the newest browsers, but not the rest. Firefox, Safari, Chrome and Opera browsers all support RGBA, but Internet Explorer does not.
Fortunately, due to the robust design of CSS as a language, we can specify RGBA colours for browsers that support it and an alternative for browsers that do not.
Falling back to solid colour
The simplest technique is to allow the browser to fall back to using a solid colour when opacity isn’t available. The CSS parsing rules specify that any unrecognised value should be ignored. We can make use of this because a browser without RGBA support will treat a colour value specified with rgba() as unrecognised and discard it.
So if we specify the colour first using rgb() for all browsers, we can then overwrite it with an rgba() colour for browsers that understand RGBA.
h1 {
color: rgb(127, 127, 127);
color: rgba(0, 0, 0, 0.5);
}
Falling back to a PNG
In cases where you’re using transparency on a background-color (although not on borders or text) it’s possible to fall back to using a PNG with alpha channel to get the same effect. This is less flexible than using CSS as you’ll need to create a new PNG for each level of transparency required, but it can be a useful solution.
Using the same principal as before, we can specify the background in a style that all browsers will understand, and then overwrite it in a way that browsers without RGBA support will ignore.
h1 {
background: transparent url(black50.png);
background: rgba(0, 0, 0, 0.5) none;
}
It’s important to note that this works because we’re using the background shorthand property, enabling us to set both the background colour and background image in a single declaration. It’s this that enables us to rely on the browser ignoring the second declaration when it encounters the unknown rgba() value.
Next Steps
The really great thing about RGBA colour is that it gives us the ability to create far more graphically rich designs without the need to use images. Not only does that make for faster and lighter pages, but sites which are easier and quicker to build and maintain. CSS values can also be changed in response to user interaction or even manipulated with JavaScript in a way that’s just not so easy using images.
Opacity can be changed on :hover or manipulated with JavaScript
div {
color: rgba(255, 255, 255, 0.8);
background-color: rgba(142, 213, 87, 0.3);
}
div:hover {
color: rgba(255, 255, 255, 1);
background-color: rgba(142, 213, 87, 0.6);
}
Clever use of transparency in border colours can help ease the transition between overlay items and the page behind.
Borders can receive the RGBA treatment, too
div {
color: rgb(0, 0, 0);
background-color: rgb(255, 255, 255);
border: 10px solid rgba(255, 255, 255, 0.3);
}
In Conclusion
That’s a brief insight into RGBA colour, what it’s good for and how it can be used whilst providing support for older browsers. With the current lack of support in Internet Explorer, it’s probably not a technique that commercial designs will want to heavily rely on right away – simply because of the overhead of needing to think about fallback all the time.
It is, however, a useful tool to have for those smaller, less critical touches that can really help to finesse a design. As browser support becomes more mainstream, you’ll already be familiar and practised with RGBA and ready to go.",2009,Drew McLellan,drewmclellan,2009-12-01T00:00:00+00:00,https://24ways.org/2009/working-with-rgba-colour/,code
182,Breaking Out The Edges of The Browser,"HTML5 contains more than just the new entities for a more meaningful document, it also contains an arsenal of JavaScript APIs. So many in fact, that some APIs have outgrown the HTML5 spec’s backyard and have been sent away to grow up all on their own and been given the prestigious honour of being specs in their own right.
So when I refer to (bendy finger quote) “HTML5”, I mean the HTML5 specification and a handful of other specifications that help us authors build web applications.
Examples of those specs I would include in the umbrella term would be: geolocation, web storage, web databases, web sockets and web workers, to name a few.
For all you guys and gals, on this special 2009 series of 24 ways, I’m just going to focus on data storage and offline applications: boldly taking your browser where no browser has gone before!
Web Storage
The Web Storage API is basically cookies on steroids, a unhealthy dosage of steroids. Cookies are always a pain to work with. First of all you have the problem of setting, changing and deleting them. Typically solved by Googling and blindly relying on PPK’s solution. If that wasn’t enough, there’s the 4Kb limit that some of you have hit when you really don’t want to.
The Web Storage API gets around all of the hoops you have to jump through with cookies. Storage supports around 5Mb of data per domain (the spec’s recommendation, but it’s open to the browsers to implement anything they like) and splits in to two types of storage objects:
sessionStorage – available to all pages on that domain while the window remains open
localStorage – available on the domain until manually removed
Support
Ignoring beta browsers for our support list, below is a list of the major browsers and their support for the Web Storage API:
Latest: Internet Explorer, Firefox, Safari (desktop & mobile/iPhone)
Partial: Google Chrome (only supports localStorage)
Not supported: Opera (as of 10.10)
Usage
Both sessionStorage and localStorage support the same interface for accessing their contents, so for these examples I’ll use localStorage.
The storage interface includes the following methods:
setItem(key, value)
getItem(key)
key(index)
removeItem(key)
clear()
In the simple example below, we’ll use setItem and getItem to store and retrieve data:
localStorage.setItem('name', 'Remy');
alert( localStorage.getItem('name') );
Using alert boxes can be a pretty lame way of debugging. Conveniently Safari (and Chrome) include database tab in their debugging tools (cmd+alt+i), so you can get a visual handle on the state of your data:
Viewing localStorage
As far as I know only Safari has this view on stored data natively in the browser. There may be a Firefox plugin (but I’ve not found it yet!) and IE… well that’s just IE.
Even though we’ve used setItem and getItem, there’s also a few other ways you can set and access the data.
In the example below, we’re accessing the stored value directly using an expando and equally, you can also set values this way:
localStorage.name = ""Remy"";
alert( localStorage.name ); // shows ""Remy""
The Web Storage API also has a key method, which is zero based, and returns the key in which data has been stored. This should also be in the same order that you set the keys, for example:
alert( localStorage.getItem(localStorage.key(0)) );
// shows ""Remy""
I mention the key() method because it’s not an unlikely name for a stored value. This can cause serious problems though.
When selecting the names for your keys, you need to be sure you don’t take one of the method names that are already on the storage object, like key, clear, etc. As there are no warnings when you try to overwrite the methods, it means when you come to access the key() method, the call breaks as key is a string value and not a function.
You can try this yourself by creating a new stored value using localStorage.key = ""foo"" and you’ll see that the Safari debugger breaks because it relies on the key() method to enumerate each of the stored values.
Usage Notes
Currently all browsers only support storing strings. This also means if you store a numeric, it will get converted to a string:
localStorage.setItem('count', 31);
alert(typeof localStorage.getItem('count'));
// shows ""string""
This also means you can’t store more complicated objects natively with the storage objects. To get around this, you can use Douglas Crockford’s JSON parser (though Firefox 3.5 has JSON parsing support baked in to the browser – yay!) json2.js to convert the object to a stringified JSON object:
var person = {
name: 'Remy',
height: 'short',
location: 'Brighton, UK'
};
localStorage.setItem('person', JSON.stringify(person));
alert( JSON.parse(localStorage.getItem('person')).name );
// shows ""Remy""
Alternatives
There are a few solutions out there that provide storage solutions that detect the Web Storage API, and if it’s not available, fall back to different technologies (for instance, using a flash object to store data). One comprehensive version of this is Dojo’s storage library. I’m personally more of a fan of libraries that plug missing functionality under the same namespace, just as Crockford’s JSON parser does (above).
For those interested it what that might look like, I’ve mocked together a simple implementation of sessionStorage. Note that it’s incomplete (because it’s missing the key method), and it could be refactored to not using the JSON stringify (but you would need to ensure that the values were properly and safely encoded):
// requires json2.js for all browsers other than Firefox 3.5
if (!window.sessionStorage && JSON) {
window.sessionStorage = (function () {
// window.top.name ensures top level, and supports around 2Mb
var data = window.top.name ? JSON.parse(window.top.name) : {};
return {
setItem: function (key, value) {
data[key] = value+""""; // force to string
window.top.name = JSON.stringify(data);
},
removeItem: function (key) {
delete data[key];
window.top.name = JSON.stringify(data);
},
getItem: function (key) {
return data[key] || null;
},
clear: function () {
data = {};
window.top.name = '';
}
};
})();
}
Now that we’ve cracked the cookie jar with our oversized Web Storage API, let’s have a look at how we take our applications offline entirely.
Offline Applications
Offline applications is (still) part of the HTML5 specification. It allows developers to build a web app and have it still function without an internet connection. The app is access via the same URL as it would be if the user were online, but the contents (or what the developer specifies) is served up to the browser from a local cache. From there it’s just an everyday stroll through open web technologies, i.e. you still have access to the Web Storage API and anything else you can do without a web connection.
For this section, I’ll refer you to a prototype demo I wrote recently of a contrived Rubik’s cube (contrived because it doesn’t work and it only works in Safari because I’m using 3D transforms).
Offline Rubik’s cube
Support
Support for offline applications is still fairly limited, but the possibilities of offline applications is pretty exciting, particularly as we’re seeing mobile support and support in applications such as Fluid (and I would expect other render engine wrapping apps).
Support currently, is as follows:
Latest: Safari (desktop & mobile/iPhone)
Sort of: Firefox‡
Not supported: Internet Explorer, Opera, Google Chrome
‡ Firefox 3.5 was released to include offline support, but in fact has bugs where it doesn’t work properly (certainly on the Mac), Minefield (Firefox beta) has resolved the bug.
Usage
The status of the application’s cache can be tested from the window.applicationCache object. However, we’ll first look at how to enable your app for offline access.
You need to create a manifest file, which will tell the browser what to cache, and then we point our web page to that cache:
For the manifest to be properly read by the browser, your server needs to serve the .manifest files as text/manifest by adding the following to your mime.types:
text/cache-manifest manifest
Next we need to populate our manifest file so the browser can read it:
CACHE MANIFEST
/demo/rubiks/index.html
/demo/rubiks/style.css
/demo/rubiks/jquery.min.js
/demo/rubiks/rubiks.js
# version 15
The first line of the manifest must read CACHE MANIFEST. Then subsequent lines tell the browser what to cache.
The HTML5 spec recommends that you include the calling web page (in my case index.html), but it’s not required. If I didn’t include index.html, the browser would cache it as part of the offline resources.
These resources are implicitly under the CACHE namespace (which you can specify any number of times if you want to).
In addition, there are two further namespaces: NETWORK and FALLBACK.
NETWORK is a whitelist namespace that tells the browser not to cache this resource and always try to request it through the network.
FALLBACK tells the browser that whilst in offline mode, if the resource isn’t available, it should return the fallback resource.
Finally, in my example I’ve included a comment with a version number. This is because once you include a manifest, the only way you can tell the browser to reload the resources is if the manifest contents changes. So I’ve included a version number in the manifest which I can change forcing the browser to reload all of the assets.
How it works
If you’re building an app that makes use of the offline cache, I would strongly recommend that you add the manifest last. The browser implementations are very new, so can sometimes get a bit tricky to debug since once the resources are cached, they really stick in the browser.
These are the steps that happen during a request for an app with a manifest:
Browser: sends request for your app.html
Server: serves all associated resources with app.html – as normal
Browser: notices that app.html has a manifest, it re-request the assets in the manifest
Server: serves the requested manifest assets (again)
Browser: window.applicationCache has a status of UPDATEREADY
Browser: reloads
Browser: only request manifest file (which doesn’t show on the net requests panel)
Server: responds with 304 Not Modified on the manifest file
Browser: serves all the cached resources locally
What might also add confusion to this process, is that the way the browsers work (currently) is if there is a cache already in place, it will use this first over updated resources. So if your manifest has changed, the browser will have already loaded the offline cache, so the user will only see the updated on the next reload.
This may seem a bit convoluted, but you can also trigger some of this manually through the applicationCache methods which can ease some of this pain.
If you bind to the online event you can manually try to update the offline cache. If the cache has then updated, swap the updated resources in to the cache and the next time the app loads it will be up to date. You could also prompt your user to reload the app (which is just a refresh) if there’s an update available.
For example (though this is just pseudo code):
addEvent(applicationCache, 'updateready', function () {
applicationCache.swapCache();
tellUserToRefresh();
});
addEvent(window, 'online', function () {
applicationCache.update();
});
Breaking out of the Browser
So that’s two different technologies that you can use to break out of the traditional browser/web page model and get your apps working in a more application-ny way.
There’s loads more in the HTML5 and non-HTML5 APIs to play with, so take your Christmas break to check them out!",2009,Remy Sharp,remysharp,2009-12-02T00:00:00+00:00,https://24ways.org/2009/breaking-out-the-edges-of-the-browser/,code
179,Have a Field Day with HTML5 Forms,"Forms are usually seen as that obnoxious thing we have to markup and style. I respectfully disagree: forms (on a par with tables) are the most exciting thing we have to work with.
Here we’re going to take a look at how to style a beautiful HTML5 form using some advanced CSS and latest CSS3 techniques. I promise you will want to style your own forms after you’ve read this article.
Here’s what we’ll be creating:
The form. (Icons from Chalkwork Payments)
Meaningful markup
We’re going to style a simple payment form. There are three main sections on this form:
The person’s details
The address details
The credit card details
We are also going to use some of HTML5’s new input types and attributes to create more meaningful fields and use less unnecessary classes and ids:
email, for the email field
tel, for the telephone field
number, for the credit card number and security code
required, for required fields
placeholder, for the hints within some of the fields
autofocus, to put focus on the first input field when the page loads
There are a million more new input types and form attributes on HTML5, and you should definitely take a look at what’s new on the W3C website. Hopefully this will give you a good idea of how much more fun form markup can be.
A good foundation
Each section of the form will be contained within its own fieldset. In the case of the radio buttons for choosing the card type, we will enclose those options in another nested fieldset.
We will also be using an ordered list to group each label / input pair. This will provide us with a (kind of) semantic styling hook and it will also make the form easier to read when viewing with no CSS applied:
The unstyled form
So here’s the markup we are going to be working with:
Making things look nice
First things first, so let’s start by adding some defaults to our form by resetting the margins and paddings of the elements and adding a default font to the page:
html, body, h1, form, fieldset, legend, ol, li {
margin: 0;
padding: 0;
}
body {
background: #ffffff;
color: #111111;
font-family: Georgia, ""Times New Roman"", Times, serif;
padding: 20px;
}
Next we are going to style the form element that is wrapping our fields:
form#payment {
background: #9cbc2c;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
padding: 20px;
width: 400px;
}
We will also remove the border from the fieldset and apply some bottom margin to it. Using the :last-of-type pseudo-class, we remove the bottom margin of the last fieldset — there is no need for it:
form#payment fieldset {
border: none;
margin-bottom: 10px;
}
form#payment fieldset:last-of-type {
margin-bottom: 0;
}
Next we’ll make the legends big and bold, and we will also apply a light-green text-shadow, to add that little extra special detail:
form#payment legend {
color: #384313;
font-size: 16px;
font-weight: bold;
padding-bottom: 10px;
text-shadow: 0 1px 1px #c0d576;
}
Our legends are looking great, but how about adding a clear indication of how many steps our form has? Instead of adding that manually to every legend, we can use automatically generated counters.
To add a counter to an element, we have to use either the :before or :after pseudo-elements to add content via CSS. We will follow these steps:
create a counter using the counter-reset property on the form element
call the counter with the content property (using the same name we’ve created before)
with the counter-incremet property, indicate that for each element that matches our selector, that counter will be increased by 1
form#payment > fieldset > legend:before {
content: ""Step "" counter(fieldsets) "": "";
counter-increment: fieldsets;
}
Finally, we need to change the style of the legend that is part of the radio buttons group, to make it look like a label:
form#payment fieldset fieldset legend {
color: #111111;
font-size: 13px;
font-weight: normal;
padding-bottom: 0;
}
Styling the lists
For our list elements, we’ll just add some nice rounded corners and semi-transparent border and background. Because we are using RGBa colors, we should provide a fallback for browsers that don’t support them (that comes before the RBGa color). For the nested lists, we will remove these properties because they would be overlapping:
form#payment ol li {
background: #b9cf6a;
background: rgba(255,255,255,.3);
border-color: #e3ebc3;
border-color: rgba(255,255,255,.6);
border-style: solid;
border-width: 2px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
line-height: 30px;
list-style: none;
padding: 5px 10px;
margin-bottom: 2px;
}
form#payment ol ol li {
background: none;
border: none;
float: left;
}
Form controls
Now we only need to style our labels, inputs and the button element.
All our labels will look the same, with the exception of the one for the radio elements. We will float them to the left and give them a width.
For the credit card type labels, we will add an icon as the background, and override some of the properties that aren’t necessary. We will be using the attribute selector to specify the background image for each label — in this case, we use the for attribute of each label.
To add an extra user-friendly detail, we’ll add a cursor: pointer to the radio button labels on the :hover state, so the user knows that he can simply click them to select that option.
form#payment label {
float: left;
font-size: 13px;
width: 110px;
}
form#payment fieldset fieldset label {
background:none no-repeat left 50%;
line-height: 20px;
padding: 0 0 0 30px;
width: auto;
}
form#payment label[for=visa] {
background-image: url(visa.gif);
}
form#payment label[for=amex] {
background-image: url(amex.gif);
}
form#payment label[for=mastercard] {
background-image: url(mastercard.gif);
}
form#payment fieldset fieldset label:hover {
cursor: pointer;
}
Almost there! Now onto the input elements. Here we want to match all inputs, except for the radio ones, and the textarea. For that we will use the negation pseudo-class (:not()). With it we can target all input elements except for the ones with type of radio.
We will also make sure to add some :focus styles and add the appropriate styling for the radio inputs:
form#payment input:not([type=radio]),
form#payment textarea {
background: #ffffff;
border: none;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-khtml-border-radius: 3px;
border-radius: 3px;
font: italic 13px Georgia, ""Times New Roman"", Times, serif;
outline: none;
padding: 5px;
width: 200px;
}
form#payment input:not([type=submit]):focus,
form#payment textarea:focus {
background: #eaeaea;
}
form#payment input[type=radio] {
float: left;
margin-right: 5px;
}
And finally we come to our submit button. To it, we will just add some nice typography and text-shadow, align it to the center of the form and give it some background colors for its different states:
form#payment button {
background: #384313;
border: none;
-moz-border-radius: 20px;
-webkit-border-radius: 20px;
-khtml-border-radius: 20px;
border-radius: 20px;
color: #ffffff;
display: block;
font: 18px Georgia, ""Times New Roman"", Times, serif;
letter-spacing: 1px;
margin: auto;
padding: 7px 25px;
text-shadow: 0 1px 1px #000000;
text-transform: uppercase;
}
form#payment button:hover {
background: #1e2506;
cursor: pointer;
}
And that’s it! See the completed form.
This form will not look the same on every browser. Internet Explorer and Opera don’t support border-radius (at least not for now); the new input types are rendered as just normal inputs on some browsers; and some of the most advanced CSS, like the counter, :last-of-type or text-shadow are not supported on some browsers. But that doesn’t mean you can’t use them right now, and simplify your development process. My gift to you!",2009,Inayaili de León Persson,inayailideleon,2009-12-03T00:00:00+00:00,https://24ways.org/2009/have-a-field-day-with-html5-forms/,code
176,What makes a website successful? It might not be what you expect!,"What makes some sites succeed and others fail? Put another way, when you are asked to redesign an existing website, what problems are you looking out for and where do you concentrate your efforts?
I would argue that as web designers we spend too much time looking at the wrong kind of problem.
I recently ran a free open door consultancy clinic to celebrate the launch of my new book (yes I know, two shameless plugs in one sentence). This involved various website owners volunteering their sites for review. Both myself and the audience then provided feedback.
What quickly became apparent is that the feedback being given by the audience was biased towards design and development.
Although their comments were excellent it focused almost exclusively on the quality of code, site aesthetics and usability. To address these issues in isolation is similar to treating symptoms and ignoring the underlying illness.
Cure the illness not the symptoms
Poor design, bad usability and terribly written code are symptoms of bigger problems. Often when we endeavour to address these symptoms, we meet resistance from our clients and become frustrated. This is because our clients are still struggling with fundamental concepts we take for granted.
Before we can address issues of aesthetics, usability and code, we need to tackle business objectives, calls to action and user tasks. Without dealing with these fundamental principles our clients’ website will fail.
Let me address each in turn:
Understand the business objectives
Do you ask your clients why they have a website? It feels like an obvious question. However, it is surprising how many clients do not have an answer.
Without having a clear idea of the siteʼs business objectives, the client has no way to know whether it is succeeding. This means they have no justification for further investment and that leads to quibbling over every penny.
However most importantly, without clearly defined business aims they have no standard against which to base their decisions. Everything becomes subjective and that will inevitably lead to problems.
Before we start discussing design, usability and development, we need to focus our clients on establishing concrete business objectives. This will provide a framework for decision making during the development phase.
This will not only help the client make decisions, it will also focus them on the business and away from micro managing the design.
Establish clear calls to action
Once business objectives have been set this opens up the possibility to establish clear calls to action.
I am amazed at how few website owners can name their calls to action. However, I am even more staggered at how few web designers ask about them.
Calls to action are not just limited to ecommerce sites. Whether you are asking people to sign up for a newsletter or complete a contact us form, every site should have a desired objective for users.
What is more, each page of a site should have micro calls to action that always draw users on and never leave them at a dead end.
Without clearly defined calls to action you cannot successfully design a site, structure the user experience or measure its success. They bring focus to the site and encourage the client to concentrate their efforts on helping people reach those goals.
Of course in order to know if a call to action is going to work, it is necessary to do some user testing.
Test against the right tasks
As web designers we all like to boast about being ʻuser centricʼ whatever that means! However, in reality I think many of us are paying lip service to the subject.
Sure, we ask our clients about who their users are and maybe even do some usability testing. However, usability testing is no good if we are not asking the right questions.
Again we find ourselves working on a superficial level rather than tackling the deeper issues.
Clients find it relatively easy to tell you who their target audience is. Admittedly the list they come back with is often overly long and contains a lot of edge cases. However, where they begin to struggle is articulating what these users will want to achieve on the website. They know who they want to reach. However, they cannot always tell you why those people would be interested in the site.
These user tasks are another fundamental building block for any successful website. Although it is important for a website owner to understand what their objectives are and what they want users to do, it is even more important that they understand the users objectives as well.
Again, this provides context for the decisions they are making about design, usability and functionality. Without it the site will become self serving, largely ignoring the needs of users.
User tasks help to focus the clientʼs mind on the needs of their user, rather than what they can get out of them.
So am I claiming that design, usability and code do not matter? Well the shocking truth is that to some extent I am!
The shocking truth
Whether we like it or not there is significant evidence that you can create a successful website with bad design, terrible code and without ever running a usability test session.
You only need to look at the design of Craigslist or the code of Amazon to see that this is true.
However, I do not believe it is possible to build a successful website without business objectives, calls to action and a clear idea of user tasks.
Do not misunderstand me. I do believe design, usability and code matters. I just believe that they only matter if the fundamentals are already in place. These things improve a solid foundation but are no use in their own right.
As web designers it is our responsibility to ensure fundamental questions are being asked, before we start exploring other issues. If we do not, our websites will look great, be well coded and have gone through endless usability tests, however it will not be truly successful.",2009,Paul Boag,paulboag,2009-12-04T00:00:00+00:00,https://24ways.org/2009/what-makes-a-website-successful/,business
177,"HTML5: Tool of Satan, or Yule of Santa?","It would lead to unseasonal arguments to discuss the title of this piece here, and the arguments are as indigestible as the fourth turkey curry of the season, so we’ll restrict our article to the practical rather than the philosophical: what HTML5 can you reasonably expect to be able to use reliably cross-browser in the early months of 2010?
The answer is that you can use more than you might think, due to the seasonal tinsel of feature-detection and using the sparkly pixie-dust of IE-only VML (but used in a way that won’t damage your Elf).
Canvas
canvas is a 2D drawing API that defines a blank area of the screen of arbitrary size, and allows you to draw on it using JavaScript. The pictures can be animated, such as in this canvas mashup of Wolfenstein 3D and Flickr. (The difference between canvas and SVG is that SVG uses vector graphics, so is infinitely scalable. It also keeps a DOM, whereas canvas is just pixels so you have to do all your own book-keeping yourself in JavaScript if you want to know where aliens are on screen, or do collision detection.)
Previously, you needed to do this using Adobe Flash or Java applets, requiring plugins and potentially compromising keyboard accessibility. Canvas drawing is supported now in Opera, Safari, Chrome and Firefox. The reindeer in the corner is, of course, Internet Explorer, which currently has zero support for canvas (or SVG, come to that).
Now, don’t pull a face like all you’ve found in your Yuletide stocking is a mouldy satsuma and a couple of nuts—that’s not the end of the story. Canvas was originally an Apple proprietary technology, and Internet Explorer had a similar one called Vector Markup Language which was submitted to the W3C for standardisation in 1998 but which, unlike canvas, was not blessed with retrospective standardisation.
What you need, then, is some way for Internet Explorer to translate canvas to VML on-the-fly, while leaving the other, more standards-compliant browsers to use the HTML5. And such a way exists—it’s a JavaScript library called excanvas. It’s downloadable from http://code.google.com/p/explorercanvas/ and it’s simple to include it via a conditional comment in the head for IE:
Simply include this, and your canvas will be natively supported in the modern browsers (and the library won’t even be downloaded) whereas IE will suddenly render your canvas using its own VML engine. Be sure, however, to check it carefully, as the IE JavaScript engine isn’t so fast and you’ll need to be sure that performance isn’t too degraded to use.
Forms
Since the beginning of the Web, developers have been coding forms, and then writing JavaScript to check whether an input is a correctly formed email address, URL, credit card number or conforms to some other pattern. The cumulative labour of the world’s developers over the last 15 years makes whizzing round in a sleigh and delivering presents seem like popping to the corner shop in comparison.
With HTML5, that’s all about to change. As Yaili began to explore on Day 3, a host of new attributes to the input element provide built-in validation for email address formats (input type=email), URLs (input type=url), any pattern that can be expressed with a JavaScript-syntax regex (pattern=""[0-9][A-Z]{3}"") and the like. New attributes such as required, autofocus, input type=number min=3 max=50 remove much of the tedious JavaScript from form validation.
Other, really exciting input types are available (see all input types). The datalist is reminiscent of a select box, but allows the user to enter their own text if they don’t want to choose one of the pre-defined options. input type=range is rendered as a slider, while input type=date pops up a date picker, all natively in the browser with no JavaScript required at all.
Currently, support is most complete in an experimental implementation in Opera and a number of the new attributes in Webkit-based browsers. But don’t let that stop you! The clever thing about the specification of the new Web Forms is that all the new input types are attributes (rather than elements). input defaults to input type=text, so if a browser doesn’t understand a new HTML5 type, it gracefully degrades to a plain text input.
So where does that leave validation in those browsers that don’t support Web Forms? The answer is that you don’t retire your pre-existing JavaScript validation just yet, but you leave it as a fallback after doing some feature detection. To detect whether (say) input type=email is supported, you make a new input type=email with JavaScript but don’t add it to the page. Then, you interrogate your new element to find out what its type attribute is. If it’s reported back as “email”, then the browser supports the new feature, so let it do its work and don’t bring in any JavaScript validation. If it’s reported back as “text”, it’s fallen back to the default, indicating that it’s not supported, so your code should branch to your old validation routines. Alternatively, use the small (7K) Modernizr library which will do this work for you and give you JavaScript booleans like Modernizr.inputtypes[email] set to true or false.
So what does this buy you? Well, first and foremost, you’re future-proofing your code for that time when all browsers support these hugely useful additions to forms. Secondly, you buy a usability and accessibility win. Although it’s tempting to style the stuffing out of your form fields (which can, incidentally, lead to madness), whatever your branding people say, it’s better to leave forms as close to the browser defaults as possible. A browser’s slider and date pickers will be the same across different sites, making it much more comprehensible to users. And, by using native controls rather than faking sliders and date pickers with JavaScript, your forms are much more likely to be accessible to users of assistive technology.
HTML5 DOCTYPE
You can use the new DOCTYPE !doctype html now and – hey presto – you’re writing HTML5, as it’s pretty much a superset of HTML4. There are some useful advantages to doing this. The first is that the HTML5 validator (I use http://html5.validator.nu) also validates ARIA information, whereas the HTML4 validator doesn’t, as ARIA is a new spec developed after HTML4. (Actually, it’s more accurate to say that it doesn’t validate your ARIA attributes, but it doesn’t automatically report them as an error.)
Another advantage is that HTML5 allows tabindex as a global attribute (that is, on any element). Although originally designed as an accessibility bolt-on, I ordinarily advise you don’t use it; a well-structured page should provide a logical tab order through links and form fields already.
However, tabindex=""-1"" is a legal value in HTML5 as it allows for the element to be programmatically focussable by JavaScript. It’s also very useful for correcting a bug in Internet Explorer when used with a keyboard; in-page links go nowhere if the destination doesn’t have a proprietary property called hasLayout set or a tabindex of -1.
So, whether it is the tool of Satan or yule of Santa, HTML5 is just around the corner. Some you can use now, and by the end of 2010 I predict you’ll be able to use a whole lot more as new browser versions are released.",2009,Bruce Lawson,brucelawson,2009-12-05T00:00:00+00:00,https://24ways.org/2009/html5-tool-of-satan-or-yule-of-santa/,code
175,Front-End Code Reusability with CSS and JavaScript,"Most web standards-based developers are more than familiar with creating their sites with semantic HTML with lots and lots of CSS. With each new page in a design, the CSS tends to grow and grow and more elements and styles are added. But CSS can be used to better effect.
The idea of object-oriented CSS isn’t new. Nicole Sullivan has written a presentation on the subject and outlines two main concepts: separate structure and visual design; and separate container and content. Jeff Croft talks about Applying OOP Concepts to CSS:
I can make a class of .box that defines some basic layout structure, and another class of .rounded that provides rounded corners, and classes of .wide and .narrow that define some widths, and then easily create boxes of varying widths and styles by assigning multiple classes to an element, without having to duplicate code in my CSS.
This concept helps reduce CSS file size, allows for great flexibility, rapid building of similar content areas and means greater consistency throughout the entire design. You can also take this concept one step further and apply it to site behaviour with JavaScript.
Build a versatile slideshow
I will show you how to build multiple slideshows using jQuery, allowing varying levels of functionality which you may find on one site design. The code will be flexible enough to allow you to add previous/next links, image pagination and the ability to change the animation type. More importantly, it will allow you to apply any combination of these features.
Image galleries are simply a list of images, so the obvious choice of marking the content up is to use a
. Many designs, however, do not cater to non-JavaScript versions of the website, and thus don’t take in to account large multiple images. You could also simply hide all the other images in the list, apart from the first image. This method can waste bandwidth because the other images might be downloaded when they are never going to be seen.
Taking this second concept — only showing one image — the only code you need to start your slideshow is an tag. The other images can be loaded dynamically via either a per-page JavaScript array or via AJAX.
The slideshow concept is built upon the very versatile Cycle jQuery Plugin and is structured in to another reusable jQuery plugin. Below is the HTML and JavaScript snippet needed to run every different type of slideshow I have mentioned above.
Slideshow plugin
If you’re not familiar with jQuery or how to write and author your own plugin there are plenty of articles to help you out.
jQuery has a chainable interface and this is something your plugin must implement. This is easy to achieve, so your plugin simply returns the collection it is using:
return this.each(
function () {}
};
Local Variables
To keep the JavaScript clean and avoid any conflicts, you must set up any variables which are local to the plugin and should be used on each collection item. Defining all your variables at the top under one statement makes adding more and finding which variables are used easier. For other tips, conventions and improvements check out JSLint, the “JavaScript Code Quality Tool”.
var $$, $div, $images, $arrows, $pager,
id, selector, path, o, options,
height, width,
list = [], li = 0,
parts = [], pi = 0,
arrows = ['Previous', 'Next'];
Cache jQuery Objects
It is good practice to cache any calls made to jQuery. This reduces wasted DOM calls, can improve the speed of your JavaScript code and makes code more reusable.
The following code snippet caches the current selected DOM element as a jQuery object using the variable name $$. Secondly, the plugin makes its settings available to the Metadata plugin‡ which is best practice within jQuery plugins.
For each slideshow the plugin generates a
with a class of slideshow and a unique id. This is used to wrap the slideshow images, pagination and controls.
The base path which is used for all the images in the slideshow is calculated based on the existing image which appears on the page. For example, if the path to the image on the page was /img/flowers/1.jpg the plugin would use the path /img/flowers/ to load the other images.
$$ = $(this);
o = $.metadata ? $.extend({}, settings, $$.metadata()) : settings;
id = 'slideshow-' + (i++ + 1);
$div = $('').addClass('slideshow').attr('id', id);
selector = '#' + id + ' ';
path = $$.attr('src').replace(/[0-9]\.jpg/g, '');
options = {};
height = $$.height();
width = $$.width();
Note: the plugin uses conventions such as folder structure and numeric filenames. These conventions help with the reusable aspect of plugins and best practices.
Build the Images
The cycle plugin uses a list of images to create the slideshow. Because we chose to start with one image we must now build the list programmatically. This is a case of looping through the images which were added via the plugin options, building the appropriate HTML and appending the resulting
to the DOM.
$.each(o.images, function () {
list[li++] = '
';
list[li++] = '';
list[li++] = '
';
});
$images = $('
').addClass('cycle-images');
$images.append(list.join('')).appendTo($div);
Although jQuery provides the append method it is much faster to create one really long string and append it to the DOM at the end.
Update the Options
Here are some of the options we’re making available by simply adding classes to the . You can change the slideshow effect from the default fade to the sliding effect. By adding the class of stopped the slideshow will not auto-play and must be controlled via pagination or previous and next links.
// different effect
if ($$.is('.slide')) {
options.fx = 'scrollHorz';
}
// don't move by default
if ($$.is('.stopped')) {
options.timeout = 0;
}
If you are using the same set of images throughout a website you may wish to start on a different image on each page or section. This can be easily achieved by simply adding the appropriate starting class to the .
// based on the class name on the image
if ($$.is('[class*=start-]')) {
options.startingSlide = parseInt($$.attr('class').replace(/.*start-([0-9]+).*/g, ""$1""), 10) - 1;
}
For example:
By default, and without JavaScript, the third image in this slideshow is shown. When the JavaScript is applied to the page the slideshow must know to start from the correct place, this is why the start class is required.
You could capture the default image name and parse it to get the position, but only the default image needs to be numeric to work with this plugin (and could easily be changed in future). Therefore, this extra specifically defined option means the plugin is more tolerant.
Previous/Next Links
A common feature of slideshows is previous and next links enabling the user to manually progress the images. The Cycle plugin supports this functionality, but you must generate the markup yourself. Most people add these directly in the HTML but normally only support their behaviour when JavaScript is enabled. This goes against progressive enhancement. To keep with the best practice progress enhancement method the previous/next links should be generated with JavaScript.
The follow snippet checks whether the slideshow requires the previous/next links, via the arrows class. It restricts the Cycle plugin to the specific slideshow using the selector we created at the top of the plugin. This means multiple slideshows can run on one page without conflicting each other.
The code creates a
using the arrows array we defined at the top of the plugin. It also adds a class to the slideshow container, meaning you can style different combinations of options in your CSS.
// create the arrows
if ($$.is('.arrows') && list.length > 1) {
options.next = selector + '.next';
options.prev = selector + '.previous';
$arrows = $('
').addClass('cycle-arrows');
$.each(arrows, function (i, val) {
parts[pi++] = '
';
});
$arrows.append(parts.join('')).appendTo($div);
$div.addClass('has-cycle-arrows');
}
The arrow array could be placed inside the plugin settings to allow for localisation.
Pagination
The Cycle plugin creates its own HTML for the pagination of the slideshow. All our plugin needs to do is create the list and selector to use. This snippet creates the pagination container and appends it to our specific slideshow container. It sets the Cycle plugin pager option, restricting it to the specific slideshow using the selector we created at the top of the plugin. Like the previous/next links, a class is added to the slideshow container allowing you to style the slideshow itself differently.
// create the clickable pagination
if ($$.is('.pagination') && list.length > 1) {
options.pager = selector + '.cycle-pagination';
$pager = $('
').addClass('cycle-pagination');
$pager.appendTo($div);
$div.addClass('has-cycle-pagination');
}
Note: the Cycle plugin creates a
with anchors listed directly inside without the surrounding
. Unfortunately this is invalid markup but the code still works.
Demos
Well, that describes all the ins-and-outs of the plugin, but demos make it easier to understand! Viewing the source on the demo page shows some of the combinations you can create with a simple , a few classes and some thought-out JavaScript.
View the demos →
Decide on defaults
The slideshow plugin uses the exact same settings as the Cycle plugin, but some are explicitly set within the slideshow plugin when using the classes you have set.
When deciding on what functionality is going to be controlled via this class method, be careful to choose your defaults wisely. If all slideshows should auto-play, don’t make this an option — make the option to stop the auto-play. Similarly, if every slideshow should have previous/next functionality make this the default and expose the ability to remove them with a class such as “no-pagination”.
In the examples presented on this article I have used a class on each . You can easily change this to anything you want and simply apply the plugin based on the jQuery selector required.
Grab your images
If you are using AJAX to load in your images, you can speed up development by deciding on and keeping to a folder structure and naming convention. There are two methods: basing the image path based on the current URL; or based on the src of the image. The first allows a different slideshow on each page, but in many instances a site will have a couple of sets of images and therefore the second method is probably preferred.
Metadata ‡
A method which allows you to directly modify settings in certain plugins, which also uses the classes from your HTML already exists. This is a jQuery plugin called Metadata. This method allows for finer control over the plugin settings themselves. Some people, however, may dislike the syntax and prefer using normal classes, like above which when sprinkled with a bit more JavaScript allows you to control what you need to control.
The takeaway
Hopefully you have understood not only what goes in to a basic jQuery plugin but also learnt a new and powerful idea which you can apply to other areas of your website.
The idea can also be applied to other common interfaces such as lightboxes or mapping services such as Google Maps — for example creating markers based on a list of places, each with different pin icons based the anchor class.",2009,Trevor Morris,trevormorris,2009-12-06T00:00:00+00:00,https://24ways.org/2009/front-end-code-reusability-with-css-and-javascript/,code
174,Type-Inspired Interfaces,"One of the things that terrifies me most about a new project is the starting point. How is the content laid out? What colors do I pick? Once things like that are decided, it becomes significantly easier to continue design, but it’s the blank page where I spend the most time.
To that end, I often start by choosing type. I don’t need to worry about colors or layout or anything else… just the right typefaces that support the art direction. (This article won’t focus on how to choose a typeface, but there are some really great resources if you interested in that sort of thing.)
And just like that, all your work is done. “Hold it just a second,” you might say. “All I’ve done is pick type. I still have to do the rest!”
To which I would reply, “Silly rabbit. You already have!” You see, picking the right typeface gets you farther than you might think. Here are a few tips on taking cues from type to design interfaces and interface elements.
Perfecting Web 2.0
If you’re going for that beloved rounded corner look, you might class it up a bit by choosing the wonderful Omnes Pro by Joshua Darden. As the typeface already has a rounded aesthetic, making buttons that fit the style should be pretty easy.
I’ve found that using multiples helps to keep your interfaces looking balanced and proportional. Noticing that the top left edge of the letter “P” has about an 12px corner radius, let’s choose a 24px radius for our button (a multiple of 2), so that we get proper rounded corners. By taking mathematical measurements from the typeface, our button looks more thought out than just “place arbitrary text on arbitrarily-sized button.” Pretty easy, eh?
What’s in a name(plate)?
Rounded buttons are pretty popular buttons nowadays, so let’s try something a bit more stylized.
Have a gander at Brothers, a sturdy face from Emigre. The chiseled edges give us a perfect cue for a stylized button. Using the same slope, you can make plated-looking buttons that fit a different kind of style.
Headlining
You might even take some cues from the style of the typeface itself. Didone serifs are known for their lack of bracketsーthat is, a gradual transition from the stem to the serif. Instead, they typically connect at a right angle. Another common characteristic is the high contrast in the strokes: very thick stems, very thin serifs.
So, when using a high contrast typeface, you can use it to your advantage to enhance hierarchy. Following our “multiples” guideline, a 12px measurement from the stems helps us create a top rule with a height of 24px (a multiple of 2). We can take the exact 1px measurement from the serif—a multiple of 1—to create the bottom rule. Voilà! I use this technique a lot.
Swashbucklers
And don’t forget the importance of visual “speed bumps” to break up long passages of text. A beautiful face like Alejandro Paul’s Ministry Script has over a thousand characters that can be manipulated or even combined to create elegant interface elements. Altering the partial differential character (∂) creates a delightful ornament that can help to guide the eye through content.
Stagger & Swagger
What about layout? How can we use typography to inform how our content is displayed?
Let’s take a typeface like Assembler. We might use this for a design that needs to feel uneasy or uncomfortable. In design terms, that might translate into using irregular shapes and asymmetry. Using the proportional distances and degrees from the perpendiculars, we could easily create a multi-column layout that jives with the general tone. And for all you skeptics that don’t think a layout like this is doable on the web, stranger things have happened.
Background texture generously offered by Bittbox.
Overall Design Direction
Finally, your typography could impact the entire look of the site, from the navigation to the interaction and everything in between. Check out how the (now-defunct) Nike Free site’s typography echoes the product itself, and in turn influences the navigation.
Find Your Type
With thousands of fonts to choose from, the possibilities are ridiculously open. From angles to radii to color to weight, you’ve got endless fodder before you. Great type designers spent countless hours slaving over these detailed letterforms; take advantage of it! Don’t feel like you have to limit yourself to the same old Helvetica and wet floors… unless your design calls for it.
Happy hunting!",2009,Dan Mall,danmall,2009-12-07T00:00:00+00:00,https://24ways.org/2009/type-inspired-interfaces/,design
172,The Construction of Instruction,"If the world were made to my specifications, all your clients would be happy to pay for a web writer to craft every sentence into something as elegant as it was functional, and the client would have planned the content so that you had it just when you asked, but we both know that won’t happen every time. Sometimes you just know they are going to write the About page, two company blog pages and a Facebook fan page before resigning their position as chief content writer and you are going to end up filling in all the details that will otherwise just be Lorem Ipsum.
Welcome to the big world of microcopy:
A man walks into a bar. The bartender nods a greeting and watches as the man scans the bottles behind the bar.
“Er, you have a lot of gin here. Is there one you would recommend?”
“Yes sir.”
Long pause.
“… Never mind, I’ll have the one in the green bottle.”
“Certainly, sir. But you can’t buy it from this part of the bar. You need to go through the double doors there.”
“But they look like they lead into the kitchen.”
“Really, sir? Well, no, that’s where we allow customers to purchase gin.”
The man walks through the doors. On the other side he is greeted by the same bartender.
“Y-you!” he stammers but the reticent bartender is now all but silent.
Unnerved, the man points to a green bottle, “Er, I’d like to buy a shot of that please. With ice and tonic water.”
The bartender mixes the drink and puts it on the bar just out of the reach of the man and looks up.
“Um, do you take cards?” the man asks, ready to present his credit card.
The bartender goes to take the card to put it through the machine.
“Wait! How much was it – with sales tax and everything? Do you take a gratuity?”
The bartender simply shrugs.
The man eyes him for a moment and decides to try his luck at the bar next door.
In the Choose Your Own Adventure version of this story there are plenty of ways to stop the man giving up. You could let him buy the gin right where he was; you could make the price more obvious; you could signpost the place to buy gin. The mistakes made by the bar and bartender are painfully obvious. And yet, there are websites losing users everyday due to the same lack of clear instruction.
A smidgen of well written copy goes a long way to reassure the nervous prospect. Just imagine if our man walked into the bar and the bartender explained that although the bar was here, sales were conducted in the next room because people were not then able to overhear the man’s card details. Instead, he is left to fend for himself. Online, we kick customers through the anonymous double doors with a merry ‘Paypal will handle your transaction!’.
Recently I worked on a site where the default error message, to account for anything happening that the developers hadn’t accounted for, was ‘SOMETHING HAS GONE WRONG!’. It might have been technically accurate but this is not how to inspire confidence in your customers that they can make a successful purchase through you. As everyone knows they can shop just fine, thank you very much, it is your site they will blame. Card declined? It’s the site. Didn’t know my email address has changed? It’s the site. Can’t log in? It’s the site.
Yes, yes. I know. None of these things are related to your site, or you the developer, but drop outs will be high and you’ll get imploring emails from your client asking you to wade knee deep into the site analytics to find a solution by testing 41 shades of blue because if it worked for Google…? Before you try a visual fix involving the Dulux paint chart breeding with a Pantone swatch, take an objective look at the information you are giving customers. How much are you assuming they know? How much are you relying on age-old labels and prompts without clarification?
Here’s a fun example for non-North Americans: ask your Granny to write out her billing address. If she looks at you blankly, tell her it is the address where the bank sends her statements. Imagine how many fewer instances of the wrong address there would be if we routinely added that information when people purchased from the UK? Instead, we rely on a language convention that hasn’t much common usage without explanation because, well, because we always have since the banks told us how we could take payments online.
So. Your client is busying themselves with writing the ultimate Facebook fan page about themselves and here you are left with creating a cohesive signup process or basket or purchase instructions. Here are five simple rules for bending puny humans to your will creating instructive instructions and constructive error messages that ultimately mean less hassle for you.
Plan what you want to say and plan it out as early as possible
This goes for all content. Walk a virtual mile in the shoes of your users. What specific help can you offer customers to actively encourage continuation and ensure a minimal amount of dropouts? Make space for that information. One of the most common web content mistakes is jamming too much into a space that has been defined by physical boundaries rather than planned out. If you manage it, the best you can hope for is that no-one notices it was a last-minute job. Mostly it reads like a bad game of Tetris with content sticking out all over the place.
Use your words
Microcopy often says a lot in a few words but without those words you could leave room for doubt. When doubt creeps in a customer wants reassurance just like Alice:
This time (Alice) found a little bottle… with the words ‘DRINK ME’ beautifully printed on it in large letters. It was all very well to say ‘Drink me,’ but the wise little Alice was not going to do that in a hurry. ‘No, I’ll look first,’ she said, ‘and see whether it’s marked “poison” or not’
Alice in Wonderland, Lewis Carroll.
Value clarity over brevity. Or a little more prosaically, “If in doubt, spell it out.” Thanks, Jeremy!
Be prepared to help
‘Login failed: email/password combination is incorrect.’
Oh.
‘Login failed: email/password combination is incorrect.
Are you typing in all capitals? Caps Lock may be on.
Have you changed your email address recently and not updated your account with us? Try your old email address first.
Can’t remember your password? We can help you reset it.’
Ah!
Be direct and be informative
There is rarely a site that doesn’t suffer from some degree of jargon. Squash it early by setting a few guidelines about what language and tone of voice you will use to converse with your users. Be consistent. Equally, try to be as specific as possible when giving error messages or instructions and allay fears upfront.
Card payments are handled by paypal but you do not need a paypal account to pay.
We will not display your email address but we might need it to contact you.
Sign up for our free trial (no credit card required).
Combine copy and visual cues, learn from others and test new combinations
While visual design and copy can work independently, they work best together. New phrases and designs are being tested all the time so take a peek at abtests.com for more ideas, then test some new ideas and add your own results. Have a look at the microcopy pool on Flickr for some wonderful examples of little words and pictures working together. And yes, you absolutely should join the group and post more examples.
A man walks into a bar. The bartender greets him in a friendly manner and asks him what he would like to drink.
“Gin and Tonic, please.”
“Yes sir, we have our house gin on offer but we also have a particularly good import here too.”
“The import, please.”
“How would you like it? With a slice of lemon? Over ice?”
“Both”
“That’s £3.80. We accept cash, cards or you could open a tab.”
“Card please.”
“Certainly sir. Move just over here so that you can’t be observed. Now, please enter your pin number.”
“Thank you.”
“And here is your drink. Do let me know if there is a problem with it. I shall just be here at the bar. Enjoy.”
Cheers!",2009,Relly Annett-Baker,rellyannettbaker,2009-12-08T00:00:00+00:00,https://24ways.org/2009/the-construction-of-instruction/,content
188,Don't Lose Your :focus,"For many web designers, accessibility conjures up images of blind users with screenreaders, and the difficulties in making sites accessible to this particular audience. Of course, accessibility covers a wide range of situations that go beyond the extreme example of screenreader users. And while it’s true that making a complex site accessible can often be a daunting prospect, there are also many small things that don’t take anything more than a bit of judicious planning, are very easy to test (without having to buy expensive assistive technology), and can make all the difference to certain user groups.
In this short article we’ll focus on keyboard accessibility and how careless use of CSS can potentially make your sites completely unusable.
Keyboard Access
Users who for whatever reason can’t use a mouse will employ a keyboard (or keyboard-like custom interface) to navigate around web pages. By default, they will use TAB and SHIFT + TAB to move from one focusable element (links, form controls and area) of a page to the next.
Note: in OS X, you’ll first need to turn on full keyboard access under System Preferences > Keyboard and Mouse > Keyboard Shortcuts. Safari under Windows needs to have the option Press Tab to highlight each item on a webpage in Preferences > Advanced enabled. Opera is the odd one out, as it has a variety of keyboard navigation options – the most relevant here being spatial navigation via Shift+Down, Shift+Up, Shift+Left, and Shift+Right).
But I Don’t Like Your Dotted Lines…
To show users where they are within a page, browsers place an outline around the element that currently has focus. The “problem” with these default outlines is that some browsers (Internet Explorer and Firefox) also display them when a user clicks on a focusable element with the mouse. Particularly on sites that make extensive use of image replacement on links with “off left” techniques this can create very unsightly outlines that stretch from the replaced element all the way to the left edge of the browser.
Outline bleeding off to the left (image-replacement example from carsonified.com)
There is a trivial workaround to prevent outlines from “spilling over” by adding a simple overflow:hidden, which keeps the outline in check around the clickable portion of the image-replaced element itself.
Outline tamed with overflow:hidden
But for many designers, even this is not enough. As a final solution, many actively suppress outlines altogether in their stylesheets. Controversially, even Eric Meyer’s popular reset.css – an otherwise excellent set of styles that levels the playing field of varying browser defaults – suppresses outlines.
html, body, div, span, applet, object, iframe ... {
...
outline: 0;
...
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
Yes, in his explanation (and in the CSS itself) Eric does remind designers to define relevant styles for :focus… but judging by the number of sites that seem to ignore this (and often remove the related comment from the stylesheet altogether), the message doesn’t seem to have sunk in.
Anyway… hurrah! No more unsightly dotted lines on our lovely design. But what about keyboard users? Although technically they can still TAB from one element to the next, they now get no default cue as to where they are within the page (one notable exception here is Opera, where the outline is displayed regardless of stylesheets)… and if they’re Safari users, they won’t even get an indication of a link’s target in the status bar, like they would if they hovered over it with the mouse.
Only Suppress outline For Mouse Users
Is there a way to allow users navigating with the keyboard to retain the standard outline behaviour they’ve come to expect from their browser, while also ensuring that it doesn’t show display for mouse users?
Testing some convoluted style combinations
After playing with various approaches (see Better CSS outline suppression for more details), the most elegant solution also seemed to be the simplest: don’t remove the outline on :focus, do it on :active instead – after all, :active is the dynamic pseudo-class that deals explicitly with the styles that should be applied when a focusable element is clicked or otherwise activated.
a:active { outline: none; }
The only minor issues with this method: if a user activates a link and then uses the browser’s back button, the outline becomes visible. Oh, and old versions of Internet Explorer notoriously get confused by the exact meaning of :focus, :hover and :active, so this method fails in IE6 and below. Personally, I can live with both of these.
Note: at the last minute before submitting this article, I discovered a fatal flaw in my test. It appears that outline still manages to appear in the time between activating a link and the link target loading (which in hindsight is logical – after activation, the link does indeed receive focus). As my test page only used in-page links, this issue never came up before. The slightly less elegant solution is to also suppress the outline on :hover.
a:hover, a:active { outline: none; }
In Conclusion
Of course, many web designers may argue that they know what’s best, even for their keyboard-using audience. Maybe they’ve removed the default outline and are instead providing some carefully designed :focus styles. If they know for sure that these custom styles are indeed a reliable alternative for their users, more power to them… but, at the risk of sounding like Jakob “blue underlined links” Nielsen, I’d still argue that sometimes the default browser behaviours are best left alone. Complemented, yes (and if you’re already defining some fancy styles for :hover, by all means feel free to also make them display on :focus)… but not suppressed.",2009,Patrick Lauke,patricklauke,2009-12-09T00:00:00+00:00,https://24ways.org/2009/dont-lose-your-focus/,code
187,A New Year's Resolution,"The end of 2009 is fast approaching. Yet another year has passed in a split second. Our Web Designing careers are one year older and it’s time to reflect on the highs and lows of 2009. What was your greatest achievement and what could you have done better? Perhaps, even more importantly, what are your goals for 2010?
Something that I noticed in 2009 is that being a web designer 24/7; it’s easy to get consumed by the web. It’s easy to get caught up in the blog posts, CSS galleries, web trends and Twitter! Living in this bubble can lead to one’s work becoming stale, boring and basically like everyone else’s work on the web. No designer wants this.
So, I say on 1st January 2010 let’s make it our New Year’s resolution to create something different, something special or even ground-breaking! Make it your goal to break the mold of current web design trends and light the way for your fellow web designer comrades!
Of course I wouldn’t let you embark on the New Year empty handed. To help you on your way I’ve compiled a few thoughts and ideas to get your brains ticking!
Don’t design for the web, just design
A key factor in creating something original and fresh for the web is to stop thinking in terms of web design. The first thing we need to do is forget the notion of headers, footers, side bars etc. A website doesn’t necessarily need any of these, so even before we’ve started we’ve already limited our design possibilities by thinking in these very conventional and generally accepted web terms. The browser window is a 2D canvas like any other and we can do with it what we like.
With this in mind we can approach web design from a fresh perspective. We can take inspiration for web design from editorial design, packaging design, comics, poster design, album artwork, motion design, street signage and anything else you can think of. Web design is way more than the just the web and by taking this more wide angled view of what web design is and can be you’ll find there are a thousand more exiting design possibilities.
Note: Try leaving the wire framing till after you’ve gone to town with some initial design concepts. You might find it helps keep your head out of that ‘web space’ a little bit longer, thus enabling you to think more freely about your design. Really go crazy with these as you can always pull it back into line later. The key is to think big initially and then work backwards. There’s no point restricting your creativity early on because your technical knowledge can foresee problems down the line. You can always sort these problems out later on… let your creative juices flow!
Inspiration can come from anywhere! (Photo: modomatic)
Try something new!
Progress in web design or in any design discipline is a sort of evolution. Design trends and solutions merge and mutate to create new design trends and hopefully better solutions. This is fine but the real leaps are made when someone has the guts to do something different.
Don’t be afraid to challenge the status quo. To create truly original work you have to be prepared to get it wrong and that’s hard to do. When you’re faced with this challenge just remind yourself that in web design there is rarely a ‘best way to do something’, or why would we ever do it any other way?
If you do this and get it right the pay off can be immense. Not only will you work stand out from the crowd by a mile, you will have become a trend setter as opposed to a trend follower.
Tell a story with your design
Great web design is way more than just the aesthetics, functionality or usability. Great web design goes beyond the pixels on the screen. For your website to make a real impact on it’s users it has to connect with them emotionally. So, whether your website is promoting your own company or selling cheese it needs to move people. You need to weave a story into your design. It’s this story that your users will connect with.
To do this the main ingredients of your design need to be strongly connected. In my head those main ingredients are Copy, Graphic Design, Typography, imagery and colour.
Copy
Strong meaningful copy is the backbone to most great web design work. Pay special attention to strap lines and headlines as these are often the sparks that start the fire. All the other elements can be inspired by this backbone of strong copy.
Graphic Design
Use the copy to influence how you treat the page with your graphic design. Let the design echo the words.
Typography
What really excites me about typography isn’t the general text presentation on a page, most half decent web designer have a grasp of this already. What excites me is the potential there is to base a whole design on words and letters. Using the strong copy you already have, one has the opportunity the customise, distort, build and arrange words and letters to create beautiful and powerful compositions that can be the basis for an entire site design.
Get creative with Typography (Photo: Pam Sattler)
Imagery and Colour
With clever use of imagery (photographs or illustrations) and colour you further have the chance to deepen the story you are weaving into your design. The key is to use meaningful imagery, don’t to insert generic imagery for the sake of filling space… it’s just a wasted opportunity.
Remember, the main elements of your design combined are greater than the sum of their parts. Whatever design decisions you make on a page, make them for a good reason. It’s not good enough to try and seduce your users with slick and shiny web pages. For your site to leave a lasting impression on the user you need to make that emotional connection.
Telling the Story (Advertising Agency: Tita, Milano, Italy, Art Director: Emanuele Basso)
Go one step further
So you’ve almost finished your latest website design. You’ve fulfilled the brief, you’re happy with the result and you’re pretty sure your client will be too. It’s at this point we should ask ourselves “Can I push this further”? What touches could you add to the site that’ll take it beyond what was required and into something exceptional? The truth is, to produce exceptional work we need to do more than is required of us. We need to answer the brief and then some!
Go back through your site and make a note of what enhancements could be made to make the site not just good but outstanding. It might be revisiting a couple of pages that were neglected in the design process, it might be adding some CSS 3 gloss for the users that can benefit from it or it might just be adding some clever little easter eggs to show that you care. These touches will soon add up and make a massive difference to the finished product.
So, go one step further… take it further than you anyone else will. Then your work will stand out for sure.
Parting message
I love being a designer for many of reasons but the main one being that with every new project we embark on we have the chance to express ourselves. We have the chance to create something special, something that people will talk about. It’s this chance that drives us onwards day after day, year after year. So in 2010 shout louder than you ever have before, take chances, try something new and above all design your socks off!",2009,Mike Kus,mikekus,2009-12-10T00:00:00+00:00,https://24ways.org/2009/a-new-years-resolution/,business
169,Incite A Riot,"Given its relatively limited scope, HTML can be remarkably expressive. With a bit of lateral thinking, we can mark up content such as tag clouds and progress meters, even when we don’t have explicit HTML elements for those patterns.
Suppose we want to mark up a short conversation:
Alice: I think Eve is watching.
Bob: This isn’t a cryptography tutorial …we’re in the wrong example!
A note in the the HTML 4.01 spec says it’s okay to use a definition list:
Another application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words.
That would give us:
Alice
:
I think Eve is watching.
Bob
:
This isn't a cryptography tutorial ...we're in the wrong example!
This usage of a definition list is proof that writing W3C specifications and smoking crack are not mutually exclusive activities. “I think Eve is watching” is not a definition of “Alice.” If you (ab)use a definition list in this way, Norm will hunt you down.
The conversation problem was revisited in HTML5. What if dt and dd didn’t always mean “definition title” and “definition description”? A new element was forged: dialog. Now the the “d” in dt and dd doesn’t stand for “definition”, it stands for “dialog” (or “dialogue” if you can spell):
Problem solved …except that dialog is no longer in the HTML5 spec. Hixie further expanded the meaning of dt and dd so that they could be used inside details (which makes sense—it starts with a “d”) and figure (…um). At the same time as the content model of details and figure were being updated, the completely-unrelated dialog element was dropped.
Back to the drawing board, or in this case, the HTML 4.01 specification. The spec defines the cite element thusly:
Contains a citation or a reference to other sources.
Perfect! There’s even an example showing how this can applied when attributing quotes to people:
As Harry S. Truman said,
The buck stops here.
For longer quotes, the blockquote element might be more appropriate. In a conversation, where the order matters, I think an ordered list would make a good containing element for this pattern:
Alice: I think Eve is watching.
Bob: This isn't a cryptography tutorial ...we're in the wrong example!
Problem solved …except that the cite element has been redefined in the HTML5 spec:
The cite element represents the title of a work … A person’s name is not the title of a work … and the element must therefore not be used to mark up people’s names.
HTML5 is supposed to be backwards compatible with previous versions of HTML, yet here we have a semantic pattern already defined in HTML 4.01 that is now non-conforming in HTML5. The entire justification for the change boils down to this line of reasoning:
Given that: titles of works are often italicised and
given that: people’s names are not often italicised and
given that: most browsers italicise the contents of the cite element,
therefore: the cite element should not be used to mark up people’s names.
In other words, the default browser styling is now dictating semantic meaning. The tail is wagging the dog.
Not to worry, the HTML5 spec tells us how we can mark up names in conversations without using the cite element:
In some cases, the b element might be appropriate for names
I believe the colloquial response to this is a combination of the letters W, T and F, followed by a question mark.
The non-normative note continues:
In other cases, if an element is really needed, the span element can be used.
This is not a joke. We are seriously being told to use semantically meaningless elements to mark up content that is semantically meaningful.
We don’t have to take it.
Firstly, any conformance checker—that’s the new politically correct term for “validator”—cannot possibly check every instance of the cite element to see if it’s really the title of a work and not the name of a person. So we can disobey the specification without fear of invalidating our documents.
Secondly, Hixie has repeatedly stated that browser makers have a powerful voice in deciding what goes into the HTML5 spec; if a browser maker refuses to implement a feature, then that feature should come out of the spec because otherwise, the spec is fiction. Well, one of the design principles of HTML5 is the Priority of Constituencies:
In case of conflict, consider users over authors over implementors over specifiers over theoretical purity.
That places us—authors—above browser makers. If we resolutely refuse to implement part of the HTML5 spec, then the spec becomes fiction.
Join me in a campaign of civil disobedience against the unnecessarily restrictive, backwards-incompatible change to the cite element. Start using HTML5 but start using it sensibly. Let’s ensure that bad advice remains fictitious.
Tantek has set up a page on the WHATWG wiki to document usage of the cite element for conversations. Please contribute to it.",2009,Jeremy Keith,jeremykeith,2009-12-11T00:00:00+00:00,https://24ways.org/2009/incite-a-riot/,code
190,Self-Testing Pages with JavaScript,"Working at an agency I am involved more and more on projects in which client side code is developed internally then sent out to a separate team for implementation. You provide static HTML, CSS and JavaScript which then get placed into the CMS and brought to life as an actual website. As you can imagine this can sometimes lead to frustrations. However many safeguards you include, handing over your code to someone else is always a difficult thing to do effectively.
In this article I will show you how you can create a JavaScript implementation checker and that will give you more time for drink based activity as your web site and apps are launched quicker and with less unwanted drama!
An all too frequent occurrence
You’ve been working on a project for weeks, fixed all your bugs and send it to be implemented. You hear nothing and assume all is going well then a few days before it’s meant to launch you get an email from the implementation team informing you of bugs in your code that you need to urgently fix.
The 24ways website with a misspelt ID for the years menu
Being paranoid you trawl through the preview URL, check they have the latest files, check your code for errors then notice that a required HTML attribute has been omitted from the build and therefore CSS or JavaScript you’ve hooked onto that particular attribute isn’t being applied and that’s what is causing the “bug”.
It takes you seconds drafting an email informing them of this, it takes then seconds putting the required attribute in and low and behold the bug is fixed, everyone is happy but you’ve lost a good few hours of your life – this time could have been better spent in the pub.
I’m going to show you a way that these kind of errors can be alerted immediately during implementation of your code and ensure that when you are contacted you know that there actually is a bug to fix. You probably already know the things that could be omitted from a build and look like bugs so you’ll soon be creating tests to look for these and alert when they are not found on the rendered page. The error is reported directly to those who need to know about it and fix it. Less errant bug reports and less frantic emails ahoy!
A page with an implementation issue and instant feedback on the problem
JavaScript selector engines to the rescue
Whether you’re using a library or indeed tapping into the loveliness of the new JavaScript Selector APIs looking for particular HTML elements in JavaScript is fairly trivial now.
For instance this is how you look for a div element with the id attribute of year (the missing attribute from top image) using jQuery (the library I’ll be coding my examples in):
if ($(‘div#year’).length) {
alert(‘win’);
}
Using this logic you can probably imagine how you can write up a quick method to check for the existence of a particular element and alert when it’s not present — but assuming you have a complex page you’re going to be repeating yourself a fair bit and we don’t want to be doing that.
Test scripts
If you’ve got a lot of complex HTML patterns that need testing across a number of different pages it makes sense to keep your tests out of production code. Chances are you’ve already got a load of heavy JavaScript assets, and when it comes to file size saving every little helps.
I don’t think that tests should contain code inside of them so keep mine externally as JSON. This also means that you can use the one set of tests in multiple places. We already know that it’s a good idea to keep our CSS and JavaScript separate so lets continue along those lines here.
The test script for this example looks like this:
{
""title"": ""JS tabs implementation test"",
""description"": ""Check that the correct HTML patterns has been used"",
""author"": ""Ross Bruniges"",
""created"": ""20th July 2009"",
""tests"": [
{
""name"": ""JS tabs elements"",
""description"": ""Checking that correct HTML elements including class/IDs are used on the page for the JS to progressively enhance"",
""selector"": ""div.tabbed_content"",
""message"": ""We couldn't find VAR on the page - it's required for our JavaScript to function correctly"",
""check_for"": {
""contains"": {
""elements"": [
""div.tab_content"", ""h2""
],
""message"": ""We've noticed some missing HTML:
VAR
please refer to the examples sent for reference""
}
}
}
]
}
The first four lines are just a little bit of meta data so we remember what this test was all about when we look at it again in the future, or indeed if it ever breaks. The tests are the really cool parts and firstly you’ll notice that it’s an array – we’re only going to show one example test here but there is no reason why you can’t place in as many as you want. I’ll explain what each of the lines in the example test means:
name – short test name, I use this in pass/fail messaging later
description – meta data for future reference
selector – the root HTML element from which your HTML will be searched
message – what the app will alert if the initial selector isn’t found
check_for – a wrapper to hold inner tests – those run if the initial selector does match
contains – the type of check, we’re checking that the selector contains specified elements
elements – the HTML elements we are searching for
message – a message for when these don’t match (VAR is substituted when it’s appended to the page with the name of any elements that don’t exist)
It’s very important to pass the function valid JSON (JSONLint is a great tool for this) otherwise you might get a console showing no tests have even been run.
The JavaScript that makes this helpful
Again, this code should never hit a production server so I’ve kept it external. This also means that the only thing that’s needed to be done by the implementation team when they are ready to build is that they delete this code.
“View the full JavaScript:/examples/self-testing-pages-with-javascript/js/tests/test_suite.js
The init function appends the test console to the page and inserts the CSS file required to style it (you don’t need to use pictures of me when tests pass and fail though I see no reason why you shouldn’t), goes and grabs the JSON file referenced and parses it. The methods to pass (tests_pass) and fail (haz_fail) the test I hope are pretty self-explanatory as is the one which creates the test summary once everything has been run (create_summary).
The two interesting functions are init_tests and confirm_html.
init_tests
init_tests:function(i,obj) {
var $master_elm = $(obj.selector);
sleuth.test_page.$logger.append(""
"" + obj.name + ""
"");
var $container = $('#test_' + i);
if (!$master_elm.length) {
var err_sum = obj.message.replace(/VAR/gi, obj.selector);
sleuth.test_page.haz_failed(err_sum, $container);
return;
}
if (obj.check_for) {
$.each(obj.check_for,function(key, value){
sleuth.test_page.assign_checks($master_elm, $container, key, value);
});
} else {
sleuth.test_page.tests_passed($container);
return;
}
}
The function gets sent the number of the current iteration (used to create a unique id for its test summary) and the current object that contains the data we’re testing against as parameters.
We grab a reference to the root element and this is used (pretty much in the example shown right at the start of this article) and its length is checked. If the length is positive we know we can continue to the inner tests (if they exist) but if not we fail the test and don’t go any further. We append the error to the test console for everyone to see.
If we pass the initial check we send the reference to the root element, message contains and the inner object to a function that in this example sends us on to confirm_html (if we had a more complex test suite it would do a lot more).
confirm_html
confirm_html:function(target_selector, error_elm, obj) {
var missing_elms = [];
$.each(obj.elements, function(i, val) {
if (!target_selector.find(val).length) {
missing_elms.push(val);
}
});
if (missing_elms.length) {
var file_list = missing_elms.join('
');
var err_sum = obj.message.replace(/VAR/gi, file_list);
sleuth.test_page.haz_failed(err_sum, error_elm);
return;
}
sleuth.test_page.tests_passed(error_elm);
return;
}
We’re again using an array to check for a passed or failed test and checking its length but this time we push in a reference to each missing element we find.
If the test does fail we’re providing even more useful feedback by informing what elements have been missed out. All the implementation team need do is look for them in the files we’ve sent and include them as expected.
No more silly implementation bugs!
Here is an example of a successful implementation.
Here are some examples of failed implementations – one which fails at finding the root node and one that has the correct root node but none of the inner HTML tests pass.
Is this all we can check for?
Certainly not!
JavaScript provides pretty easy ways to check for attributes, included files (if the files being checked for are being referenced correctly and not 404ing) and even applied CSS.
Want to check that those ARIA attributes are being implemented correctly or that all images contain an alt attribute well this simple test suite can be extended to include tests for this – the sky is pretty much up to your imagination.",2009,Ross Bruniges,rossbruniges,2009-12-12T00:00:00+00:00,https://24ways.org/2009/self-testing-pages-with-javascript/,process
171,Rock Solid HTML Emails,"At some stage in your career, it’s likely you’ll be asked by a client to design a HTML email. Before you rush to explain that all the cool kids are using social media, keep in mind that when done correctly, email is still one of the best ways to promote you and your clients online. In fact, a recent survey showed that every dollar spent on email marketing this year generated more than $40 in return. That’s more than any other marketing channel, including the cool ones.
There are a whole host of ingredients that contribute to a good email marketing campaign. Permission, relevance, timeliness and engaging content are all important. Even so, the biggest challenge for designers still remains building an email that renders well across all the popular email clients.
Same same, but different
Before getting into the details, there are some uncomfortable facts that those new to HTML email should be aware of. Building an email is not like building for the web. While web browsers continue their onward march towards standards, many email clients have stubbornly stayed put. Some have even gone backwards. In 2007, Microsoft switched the Outlook rendering engine from Internet Explorer to Word. Yes, as in the word processor. Add to this the quirks of the major web-based email clients like Gmail and Hotmail, sprinkle in a little Lotus Notes and you’ll soon realize how different the email game is.
While it’s not without its challenges, rest assured it can be done. In my experience the key is to focus on three things. First, you should keep it simple. The more complex your email design, the more likely is it to choke on one of the popular clients with poor standards support. Second, you need to take your coding skills back a good decade. That often means nesting tables, bringing CSS inline and following the coding guidelines I’ll outline below. Finally, you need to test your designs regularly. Just because a template looks nice in Hotmail now, doesn’t mean it will next week.
Setting your lowest common denominator
To maintain your sanity, it’s a good idea to decide exactly which email clients you plan on supporting when building a HTML email. While general research is helpful, the email clients your subscribers are using can vary significantly from list to list. If you have the time there are a number of tools that can tell you specifically which email clients your subscribers are using. Trust me, if the testing shows almost none of them are using a client like Lotus Notes, save yourself some frustration and ignore it altogether.
Knowing which email clients you’re targeting not only makes the building process easier, it can save you lots of time in the testing phase too. For the purpose of this article, I’ll be sharing techniques that give the best results across all of the popular clients, including the notorious ones like Gmail, Lotus Notes 6 and Outlook 2007. Just remember that pixel perfection in all email clients is a pipe dream.
Let’s get started.
Use tables for layout
Because clients like Gmail and Outlook 2007 have poor support for float, margin and padding, you’ll need to use tables as the framework of your email. While nested tables are widely supported, consistent treatment of width, margin and padding within table cells is not. For the best results, keep the following in mind when coding your table structure.
Set the width in each cell, not the table
When you combine table widths, td widths, td padding and CSS padding into an email, the final result is different in almost every email client. The most reliable way to set the width of your table is to set a width for each cell, not for the table itself.
Never assume that if you don’t specify a cell width the email client will figure it out. It won’t. Also avoid using percentage based widths. Clients like Outlook 2007 don’t respect them, especially for nested tables. Stick to pixels. If you want to add padding to each cell, use either the cellpadding attribute of the table or CSS padding for each cell, but never combine the two.
Err toward nesting
Table nesting is far more reliable than setting left and right margins or padding for table cells. If you can achieve the same effect by table nesting, that will always give you the best result across the buggier email clients.
Use a container table for body background colors
Many email clients ignore background colors specified in your CSS or the tag. To work around this, wrap your entire email with a 100% width table and give that a background color.
Your email code goes here.
You can use the same approach for background images too. Just remember that some email clients don’t support them, so always provide a fallback color.
Avoid unnecessary whitespace in table cells
Where possible, avoid whitespace between your
tags. Some email clients (ahem, Yahoo! and Hotmail) can add additional padding above or below the cell contents in some scenarios, breaking your design for no apparent reason.
CSS and general font formatting
While some email designers do their best to avoid CSS altogether and rely on the dreaded tag, the truth is many CSS properties are well supported by most email clients. See this comprehensive list of CSS support across the major clients for a good idea of the safe properties and those that should be avoided.
Always move your CSS inline
Gmail is the culprit for this one. By stripping the CSS from the and of any email, we’re left with no choice but to move all CSS inline. The good news is this is something you can almost completely automate. Free services like Premailer will move all CSS inline with the click of a button. I recommend leaving this step to the end of your build process so you can utilize all the benefits of CSS.
Avoid shorthand for fonts and hex notation
A number of email clients reject CSS shorthand for the font property. For example, never set your font styles like this.
p {
font:bold 1em/1.2em georgia,times,serif;
}
Instead, declare the properties individually like this.
p {
font-weight: bold;
font-size: 1em;
line-height: 1.2em;
font-family: georgia,times,serif;
}
While we’re on the topic of fonts, I recently tested every conceivable variation of @font-face across the major email clients. The results were dismal, so unfortunately it’s web-safe fonts in email for the foreseeable future.
When declaring the color property in your CSS, some email clients don’t support shorthand hexadecimal colors like color:#f60; instead of color:#ff6600;. Stick to the longhand approach for the best results.
Paragraphs
Just like table cell spacing, paragraph spacing can be tricky to get a consistent result across the board. I’ve seen many designers revert to using double or DIVs with inline CSS margins to work around these shortfalls, but recent testing showed that paragraph support is now reliable enough to use in most cases (there was a time when Yahoo! didn’t support the paragraph tag at all).
The best approach is to set the margin inline via CSS for every paragraph in your email, like so:
p {
margin: 0 0 1.6em 0;
}
Again, do this via CSS in the head when building your email, then use Premailer to bring it inline for each paragraph later.
If part of your design is height-sensitive and calls for pixel perfection, I recommend avoiding paragraphs altogether and setting the text formatting inline in the table cell. You might need to use table nesting or cellpadding / CSS to get the desired result. Here’s an example:
your height sensitive text
Links
Some email clients will overwrite your link colors with their defaults, and you can avoid this by taking two steps. First, set a default color for each link inline like so:
this is a link
Next, add a redundant span inside the a tag.
this is a link
To some this may be overkill, but if link color is important to your design then a superfluous span is the best way to achieve consistency.
Images in HTML emails
The most important thing to remember about images in email is that they won’t be visible by default for many subscribers. If you start your design with that assumption, it forces you to keep things simple and ensure no important content is suppressed by image blocking.
With this in mind, here are the essentials to remember when using images in HTML email:
Avoid spacer images
While the combination of spacer images and nested tables was popular on the web ten years ago, image blocking in many email clients has ruled it out as a reliable technique today. Most clients replace images with an empty placeholder in the same dimensions, others strip the image altogether. Given image blocking is on by default in most email clients, this can lead to a poor first impression for many of your subscribers. Stick to fixed cell widths to keep your formatting in place with or without images.
Always include the dimensions of your image
If you forget to set the dimensions for each image, a number of clients will invent their own sizes when images are blocked and break your layout. Also, ensure that any images are correctly sized before adding them to your email. Some email clients will ignore the dimensions specified in code and rely on the true dimensions of your image.
Avoid PNGs
Lotus Notes 6 and 7 don’t support 8-bit or 24-bit PNG images, so stick with the GIF or JPG formats for all images, even if it means some additional file size.
Provide fallback colors for background images
Outlook 2007 has no support for background images (aside from this hack to get full page background images working). If you want to use a background image in your design, always provide a background color the email client can fall back on. This solves both the image blocking and Outlook 2007 problem simultaneously.
Don’t forget alt text
Lack of standards support means email clients have long destroyed the chances of a semantic and accessible HTML email. Even still, providing alt text is important from an image blocking perspective. Even with images suppressed by default, many email clients will display the provided alt text instead. Just remember that some email clients like Outlook 2007, Hotmail and Apple Mail don’t support alt text at all when images are blocked.
Use the display hack for Hotmail
For some inexplicable reason, Windows Live Hotmail adds a few pixels of additional padding below images. A workaround is to set the display property like so.
img {display:block;}
This removes the padding in Hotmail and still gives you the predicable result in other email clients.
Don’t use floats
Both Outlook 2007 and earlier versions of Notes offer no support for the float property. Instead, use the align attribute of the img tag to float images in your email.
If you’re seeing strange image behavior in Yahoo! Mail, adding align=“top” to your images can often solve this problem.
Video in email
With no support for JavaScript or the object tag, video in email (if you can call it that) has long been limited to animated gifs. However, some recent research I did into the HTML5 video tag in email showed some promising results.
Turns out HTML5 video does work in many email clients right now, including Apple Mail, Entourage 2008, MobileMe and the iPhone. The real benefit of this approach is that if the video isn’t supported, you can provide reliable fallback content such as an animated GIF or a clickable image linking to the video in the browser.
Of course, the question of whether you should add video to email is another issue altogether. If you lean toward the “yes” side check out the technique with code samples.
What about mobile email?
The mobile email landscape was a huge mess until recently. With the advent of the iPhone, Android and big improvements from Palm and RIM, it’s becoming less important to think of mobile as a different email platform altogether.
That said, there are a few key pointers to keep in mind when coding your emails to get a decent result for your more mobile subscribers.
Keep the width less than 600 pixels
Because of email client preview panes, this rule was important long before mobile email clients came of age. In truth, the iPhone and Pre have a viewport of 320 pixels, the Droid 480 pixels and the Blackberry models hover around 360 pixels. Sticking to a maximum of 600 pixels wide ensures your design should still be readable when scaled down for each device. This width also gives good results in desktop and web-based preview panes.
Be aware of automatic text resizing
In what is almost always a good feature, email clients using webkit (such as the iPhone, Pre and Android) can automatically adjust font sizes to increase readability. If testing shows this feature is doing more harm than good to your design, you can always disable it with the following CSS rule:
-webkit-text-size-adjust: none;
Don’t forget to test
While standards support in email clients hasn’t made much progress in the last few years, there has been continual change (for better or worse) in some email clients. Web-based providers like Yahoo!, Hotmail and Gmail are notorious for this. On countless occasions I’ve seen a proven design suddenly stop working without explanation.
For this reason alone it’s important to retest your email designs on a regular basis. I find a quick test every month or so does the trick, especially in the web-based clients. The good news is that after designing and testing a few HTML email campaigns, you will find that order will emerge from the chaos. Many of these pitfalls will become quite predictable and your inbox-friendly designs will take shape with them in mind.
Looking ahead
Designing HTML email can be a tough pill for new designers and standardistas to swallow, especially given the fickle and retrospective nature of email clients today. With HTML5 just around the corner we are entering a new, uncertain phase. Will email client developers take the opportunity to repent on past mistakes and bring email clients into the present? The aim of groups such as the Email Standards Project is to make much of the above advice as redundant as the long-forgotten