Oli Studholme

Oli Studholme is a designer based in Osaka, Japan, and a master of the dark arts of HTML, CSS, semantic markup, and browser idiosyncrasies. The articles he publishes on his blog oli.jp, as well as his frequent contributions on HTML5 Doctor, have gained him a reputation as a connoisseur of all things HTML5, and have greatly contributed to making the latest version of the hypertext markup language a less obscure, frightening topic for many developers. He’s also one of the authors of “Beginning HTML5 and CSS3 — The Web Evolved” (Apress).

When not working hermeneutic magic on the specs, Oli tweets @boblet too.

Published Thoughts

The secret ingredient

In my previous article I wrote about “Getting a dream job”, but there’s an aspect I didn’t mention, without which your job (and the work you produce) will probably never surpass merely so-so. Working professionally on the web is almost always a team sport now, there’s just too much for any one person to know. Even if you are a one-person shop, you are still collaborating with a client.

That secret ingredient is trust.

You need to trust your colleagues to deliver what they promise, or to have your back during crunch. You need to trust your bosses to keep you in the loop, and to stand by you even when things go pear-shaped. If you don’t have that feeling in your current job, start looking for somewhere better. If you are the boss, it can be difficult to give tasks to your team and trust they’ll deliver, especially when it’s something you can do. However by trusting them and leaving them to it, they’ll often exceed your expectations.

I feel incredibly lucky to work with people I trust implicitly at iA, and I think our trust in each other is a big part of why together we do great work.

Work with great people, people you can trust.

Getting a dream job

Questions about “necessary qualifications” in our field are evergreen, and there’s been recent discussion about the “GitHub is your resumé” idea. However, I’d like to ignore that and approach getting a job from the other end: what are employers looking for? Let’s generalize!

Think like your future boss

What is your future boss looking for in an employee? We can break this down into three broad categories:

Hard skills are the ones we generally focus on — whether you can write clean code, or design a sweet interface. An expert can generally gauge this by looking at your previous work, and discussing the thinking that went into it with you (this second part is key). Even at first glance average work can be worthwhile if you can explain the thinking (and requirements) behind it, so be able to show your working. Qualifications are generally not so important, so don’t worry if you lack them (most of us do).

Soft skills include things most of us haven’t thought about since high school career advice class, but these are also essential, and harder for a potential employer to assess. These include things like:

  • Communication skills: The ability to listen, communicate clearly what you’re doing and why, and speak & write (at least) passably ← not doing so can look sloppy, so work on this if you know you need to.
  • Dedication: A love for your profession, the desire to do things the right way rather than the easy way (and not be motivated solely by money or ego), and to be always learning.
  • Maturity: It seems strange to mention this, but being organized, being able to work autonomously, doing what you say you will (dependability), and loyalty are surprisingly not as universal as you’d think. This also includes things like not changing frameworks to the latest hotness mid-project, just because.
  • Not being “that guy”: It takes all sorts, but good personal hygiene and social awareness definitely help. Not that this applies to you, dear reader, but not being an asshole is also important. Bottom line: you have to be someone other employees can cope interacting with for 8+ hours a day.

“Fit” is the third category, and perhaps the one you can do the least about. You have to be a good fit for the team, both in terms of your skill set and your ability to work with them. It helps if you share some of the team’s common values, and of course if you’re a team player. As a wise person once told me, “The right person in the wrong team, company or job is the wrong person.” A good manager should also want to make sure the job, company, and career path fit you. If you’re not doing something that challenges you, makes you happy, and lets you grow, it won’t be good for either party.

How to get your dream job

This is where things get tricky. Generally we focus on improving our hard skills, and a great way to show this is by documenting your progress on a weblog. It also lets you practice communicating ideas clearly. Try to keep tabs on (and experiment with) what’s new in your field. You can keep up with the play by following people’s blogs or on Twitter, and by going to events and meetups.

Find people (and companies) you’d like to work with then follow their stuff, give useful feedback (for example, pointing out a typo is always appreciated), and ask questions. By doing so you’ll get to know like-minded people naturally, without needing to stray into the shady realms of “networking”. A lot of finding a great job is luck, and forming these connections can be a great way to find out about work.

If you really want to work at a specific company and think you have what it takes, meet someone who works there (or send them a short, memorable note), and say so. They may not have something suitable for you right then, so make a point to touch base occasionally to see how they’re going and if there’s anything you can help with. If you’re already a fan it helps the employer because you’ll share values, and be more likely to be a good fit. It can lead to an internship or a short-term project, which can easily lead to bigger things. When approaching people be respectful of their time, and don’t feel offended if nothing happens initially. It takes time to form a relationship — play the long game.

Try to think like an employer — what can you bring to the table? Don’t feel overwhelmed by how little you know when you’re just starting out, as employers are also looking for “potential”, and getting an internship with a good company is a great opportunity. Also, make sure you’re genuine. Lying about your skills or spamming people almost always backfires — even a hint of insincerity is a red flag.

Finally and most importantly, always be learning and challenging yourself. Work to become the person an employer wants to hire, someone with both hard and soft skills.


It’s 10 years since Joel Spolsky’s article “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)”. NotePad still saves in ASCII by default. Many web developers still don’t know about character encoding. And I’m still getting mojibake (garbled text) web pages, and errors like this:

Running "compass:site_prod" (compass) task
Encoding::CompatibilityError on line ["28"] of /Users/oli/.rvm/gems/ruby-2.0.0-p247/gems/sass-3.2.9/lib/sass/tree/visitors/to_css.rb: incompatible character encodings: UTF-8 and ASCII-8BIT
Run with --trace to see the full backtrace

I’m not going to lie to you, encoding and other internationalization stuff can be hard work. But we’re not in the business of easy. We’re in the business of doing it right. If you don’t know about unicode and internationalization, it’s time to find out. Onward!


This is how computers map ones and zeroes to characters. Back in the day there was US-ASCII, which encoded 128 characters in 7-bit binary. Localized variants were introduced to accommodate foreign languages, leading to 8-bit ISO 8859-based encodings, and a whole mess of problems with incompatible encoding.

Unicode attempts to resolve this mess, and currently contains codepoints for more than 110,000 characters, covering 100 scripts. While there are a ton of encodings you could use, for the web use UTF-8. You want to use UTF-8 for your entire stack. So how do we get that?


First up, make sure your browsers auto-detect encoding, and set UTF-8 as the fallback. This should be the default.

Text editors

Your text editor should be set to always save documents as UTF-8. Luckily modern text editors already default to this. In general, don’t save a Byte Order Mark (BOM) — it’s not needed for UTF-8, and historically could cause problems.

Declaring character encoding

According to HTML5, browsers determine an HTML page’s encoding using the following encoding sniffing steps:

  1. A user-set encoding, if there is one
  2. A Byte Order Mark
  3. An HTTP charset declaration in the web server’s response headers (Content-Type:text/html; charset=UTF-8)
  4. A <meta charset=""> declaration in the HTML page’s <head> (HTML5 style)
  5. A <meta http-equiv=""> element declaring charset in the HTML page’s <head> (old-skool HTML 4.1 etc. style)
  6. Heuristic analysis (= advanced guessing)

Web server

You want your web server to be sending the right charset declaration header (Content-Type:text/html; charset=UTF-8), or at least not sending a wrong one. You can check this in the Network tab of your browser’s developer tools — select the html page and look for Content-Type in the headers. You can also use tools such as the W3C Internationalization Checker.

If you’re using an Apache server that’s sending a non-UTF-8 charset header and you can edit .htaccess, you can set charset headers there:

AddCharset utf-8 .html .htm .php .css .js

This could also be set as part of setting the MIME type (although MIME types should already be set in Apache’s mime.types file):

AddType 'text/html; charset=utf-8' .html .htm .php
AddType 'text/css; charset=utf-8' .css
AddType 'text/javascript; charset=utf-8' .js

Alternatively, if your URIs don’t use file type extensions via mod_negotiation (and they shouldn’t), Apache is pre-configured in httpd-languages.conf to treat file names that contain .utf8 as UTF-8. This means documents named like index.utf8.html get the correct character set headers.

For those who can’t change incorrect server headers, the HTML5 spec recently reordered the encoding sniffing steps to put the BOM above HTTP headers, so you have recourse. However, not all browsers support this, so it would be better to ask your server admin to fix this (or get a better server).

For information on setting headers for other servers, and in server side scripting languages, see Setting the HTTP charset parameter by Martin Dürst and Richard Ishida.


Even if you’ve set HTTP headers, it’s a good idea to also add charset declarations to your documents.

Add <meta charset="UTF-8" /> to your HTML5 document’s <head>, ideally immediately after the opening <head> tag. It must appear in the first 1024 bytes of your document, so place it before any ASCII art.

Browsers use a similar algorithm for CSS. For external stylesheets, the CSS equivalent of HTML’s <meta charset="utf-8"> is @charset "utf-8"; at the top of your stylesheet — it must be the first thing in the CSS file. Embedded stylesheets use the encoding of the HTML page.

JavaScript doesn’t have an equivalent character set declaration method, but this is normally not a problem. However, you can declare encoding for a script with the charset attribute: <script charset="utf-8" src="[…]></script>. Don’t add charset to an embedded script — these take the encoding of the HTML page.


We’ve covered declaring encoding, the most important step, above.

Next, if you’ve got any forms for user-submitted data, add the accept-charset attribute so the browser sends UTF-8-encoded data:

html<form action="[…]" accept-charset="UTF-8">…</form>

If you’re using <input type="email"> it’s nice to validate it client-side using HTML5’s handy pattern attribute. You may be tempted to use something like [a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4} — don’t! We have multi-byte URLs now, and you need to use a pattern like [^ @]@[^ @] to support them.

Because we’re using UTF-8 we also no longer need to use escape codes such as and for curly quotes (“”) and the like — we can just add these characters directly. While it won’t hurt if you do escape things, the only characters you need to escape when using literally in UTF-8-encoded HTML5 are:

  • < Less-than sign → <
  • & Ampersand → &

You’ll also need to escape " Quotation mark (→ ") or ' Apostrophe (→ ') if you use them in attribute text, such as an alt tag (or just use their “smart” equivalents). Here’s a table on how to type quotation characters directly.

Next, declare a page’s language by using the lang attribute. First, set the document’s main language in the HTML tag. For example, a mainly Japanese document would use the language tag ja:

<html lang="ja">

To find out a language’s tag, search for the language using Richard Ishida’s Language Subtag Lookup. You can add further information, such as a dialect (en-US for American English) or script (ja-latn for Romanized Japanese), but only do so if it adds important information. If you then want to include text in other languages on the page, add the appropriate lang=" attribute to an element wrapping the text.

HTML5 relaxes the restrictions on valid ID names, so you can now use nearly anything as an ID name, such as id="☺" or id="大事", the same as class names. Keep in mind you’ll need to use character escapes in CSS for some class and ID names.


For the lowdown on character escapes in JavaScript, see JavaScript character escape sequences by Mathias Bynens. It also includes a handy JavaScript string escaping tool. For more details, see Unicode and JavaScript by Dr. Axel Rauschmayer.


MySQL defaults to the character set of latin1 and collation of latin1_swedish_ci, which turns your data into a ticking time bomb. You can check what character set and collation you’re using via this MySQL command:

SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';

While you can set MySQL up to use DEFAULT CHARACTER SET utf8 and DEFAULT COLLATE utf8_general_ci, this does not give full UTF-8 support. It only supports the Basic Multilingual Plane (BMP) of UTF-8, and will lead to data loss if you insert glyphs from other planes, such as emoji. At the time of writing this is also what many CMSes use by default (WordPress, Drupal), so be wary of this.

However, MySQL 5.5.3 adds full UTF-8 support via the charset utf8mb4. To change to utf8mb4 read Mathias Bynens’ article How to support full Unicode in MySQL databases.

Encoding issues don’t muck around: the recently released WordPress 3.6.1 fixes a PHP object injection bug that can lead to remote code execution, due to using unserialize() with MySQL’s utf8 rather than utf8mb4.


Some languages require you to specify encoding, and you’ll generally need to declare your database’s character set and collation. Some also have encoding-related functions that e.g. default to Latin-1 (ahem, PHP) to catch you out. Never assume that the data you’re dealing with is UTF-8 — ASCII appears identical unless you view the hex to see if each character is taking one byte (ASCII) or three (UTF-8). Use a string like “Iñtërnâtiônàlizætiøn” to check this.

Once you’ve read Joel’s post, read What Every Programmer Absolutely, Positively Needs To Know About Encodings And Character Sets To Work With Text, by David C. Zentgraf.

I hope that’s given you enough to get started. For more information, read the following links:

Happy internationalizing! ^_^b

You’re doing it wrong

Fifteen years ago it was “best viewed in” browser balkanization.
Ten years ago it was broken browser sniffing.
Five years ago it was breaking the Back button with JavaScript.
Now it’s meta name="viewport" with user-scalable="no".

I don’t care what your reasons are. Stop breaking my damn browser.

The nature of things

The Iga pottery festival was last weekend. This wabi-sabi style of Japanese pottery is the opposite of fine china: it’s rough, unmistakably a lump of clay, the kind of earthenware you could imagine finding in a rustic farmhouse. Like Popeye, it is what it is, and this gives it an honest beauty.

Iga ash glaze medium plate, Manabu Atarashii (link)

In architecture, Tadao Ando has become famous for buildings of simple beauty with the concrete left exposed, including the depressions from the concrete framing. Traditional Japanese knives are also plain, yet more beautiful for it. These examples are true to the nature of their materials. There’s no need for ornamentation.

So what is the intrinsic nature of the web?

From a practical perspective, web design is 95% typography. More fundamentally, we can see the inclusive, humanist underpinnings of the web in the HTML Design Principles. These include ideas such as universal access, the priority of constituencies, and interoperability. Responsive Web Design is an expression of this humane outlook.

Philosophically, I see the web’s intrinsic nature in storytelling: communication between people. A simple and beautiful example is Hi, a “networked storytelling tool” from Craig Mod, Chris Palmieri, and AQ Works.

The web is not TV, or print design, or any of the things that have come before. It is what it is. And we’re still collectively figuring it out.

Testing the web

Earlier this month I took part in Test the Web Forward Tokyo, a wonderful event organized by Adobe, Google, HTML5J and friends on testing the web. Here’s a brief overview, then I’ll tell you why you should be testing the web too.

Historically W3C specifications have been a little on the ambiguous side. This led to differing implementations (like list indentation), and major pain for developers. In the last few years specs have become a lot more explicit — for example, HTML error handling is finally specified in HTML5. However, they can still contain small problems and ambiguities, things that are often not discovered until the spec is being implemented and used. Also, with the breakneck pace of implementation there are still plenty of browser bugs.

One way you can reduce programming bugs is to write tests, and user agent developers do this to check things work as expected. However, as things become more complex it’s hard to cover all the possibilities, and there are inevitably bugs that were never found during testing because they were never tested for. Each engine doing this themselves also means a lot of duplication.

Recognizing this, the W3C has championed creating and collecting unit tests for their Test Suites. By making one large collection of tests user agent developers can all use, they don’t need to create tests for every facet of every spec themselves to check their work. Any tests they do make can be submitted for other UAs to use. Making a test requires reading a specification in detail, which helps to discover any inconsistencies or errors. This gives specification editors additional feedback, helping them fix mistakes and clarify things before widespread implementation.

More explicit specifications and more testing have both contributed to a reduction in browser bugs, and a corresponding increase in interoperability. Now we can finally begin to expect things written to the specifications to work first time in modern browsers, a fantastic improvement.

So if tests help spec editors and user agents get it right first time, and give us better specs, fewer bugs, and more interoperability, what’s the catch? Well, someone has to make them. Luckily this isn’t difficult — if you can write HTML or CSS, you can make a test. It’s basically the same as making a bug reduction — work out the feature you want to test, then make the simplest thing you can that tests that feature, and only that feature. It should be obvious enough that your Grandma or Grandpa can tell if it passed or failed.

If you want to give it a try, the steps are:

  1. Read through the resources on Test the Web Forward, especially How to Write a Reftest.
  2. Get a GitHub account and fork the HTML5 and/or CSS testing repos, following these GitHub instructions.
  3. Work out what feature of a specification you want to test for, and check there aren’t any tests for that already. For CSS tests, search in Shepherd, the CSS Test Suite Manager. Make sure you’re using the most up-to-date version of the spec (usually the Editor’s Draft)!
  4. Duplicate a starter file (examples) or a similar test, then edit it. Make sure you have a test file that tests the feature and describes the test, and a reference file showing what the test should look like when it passes, both with the correct metadata.
  5. Check that your test passes when it’s meant to and fails when it should, and that a non-technical person can understand the difference just by looking.
  6. Once your tests are ready to submit, follow those GitHub instructions again to set up a Pull Request.

After you finish your first test, it’s really easy to modify it to test related things. Once you get into it, making tests feels like a game, where you generally progress smoothly, then occasionally get a boss battle with a browser bug or ambiguous bit of the spec. If this happens make sure to report the bug, or let the spec editors know what’s confusing. If you find something wrong in the spec, you just hit the jackpot!

For an example of this in action, read Rodney Rehm’s article “CSS3 Transitions: Thank God We Have A Specification!”. Rodney turned over the stone of CSS Transitions and Animations, and found a mass of browser bugs and inconsistencies. His article and tests have led to bug reports and proposed spec improvements. By doing so, he’s made the web better for all of us. Respect! The best thing is there are plenty of features that still lack tests, and most likely still have bugs and spec issues. We can all contribute.

The best way to make your first test is to join a Test the Web Forward event. If there’s not one coming up near you, consider organizing your own testing event with some friends. It’s a fun way to learn about one aspect of HTML or CSS in detail. More importantly, making tests helps interoperability, and interoperability helps us. We can all help reduce browser bugs, and improve the specifications we use every day.

So what are you waiting for? Show your ♡, and let’s move the web forward!

CSS: reset or normalize?

Building for the web can be like building on quicksand. Browsers have tended to do mostly the same thing, but have occasional, maddeningly unpredictable differences. For example, browsers all come with “user agent stylesheets” — a default set of CSS styles, so that a heading looks like a heading etc., even before you style the page1. Of course, every browser engine uses a slightly different set of defaults.

One example of this was default list styles, where Internet Explorer and Opera initially2 indented lists with margin-left: 30pt; in their default browser stylesheets, while Firefox and KHTML went with padding-left: 40px;. If you wanted to change the default indent, specifying ul {padding-left: 0;} would lead to very different results across browsers.

CSS resets3

To get a little stability, some developers reset all margins and padding using the universal selector:

* {margin: 0; padding: 0;}

With this at the start of your stylesheet, when you specified a list indent you got what you expected. However, using * meant the default margin and padding were nuked for all elements, which became painful as soon as you added a <form> element.

Tantek Çelik and Eric Meyer started discussing a more targeted way to address user agent style differences in 2004, with the YUI CSS Reset appearing in 2006, and the Meyer Reset in 2007.

The point of a reset is to zero out as much as possible … [and] to serve as a starting point for your own baseline styles — Eric Meyer

Here’s the first rule of Eric’s current (v2.0) CSS Reset:

html, body, div, span, applet, object, iframe,
 h1, h2, h3, h4, h5, h6, p, blockquote, pre,
 a, abbr, acronym, address, big, cite, code,
 del, dfn, em, img, ins, kbd, q, s, samp,
 small, strike, strong, sub, sup, tt, var,
 b, u, i, center,
 dl, dt, dd, ol, ul, li,
 fieldset, form, label, legend,
 table, caption, tbody, tfoot, thead, tr, th, td,
 article, aside, canvas, details, embed, 
 figure, figcaption, footer, header, hgroup, 
 menu, nav, output, ruby, section, summary,
 time, mark, audio, video {
 	margin: 0;
 	padding: 0;
 	border: 0;
 	font-size: 100%;
 	font: inherit;
 	vertical-align: baseline;

This resets several properties on many (but not all) elements back to the equivalent of plain text. Because only appropriate elements are reset, this avoids some of the problems of * {margin: 0; padding: 0;}. We can then define styles for these reset “unstyled” properties, safe in the knowledge we’re building on a stable, cross-browser base. This “unstyled” styling also acts as a reminder to consciously set appropriate styles for these elements.

Problems with CSS resets

CSS resets have been a lifesaver, but especially with the rise of frameworks they are now often used as-is. For example, Eric assumed people would build on the reset styles he proposed, overriding them as appropriate, and version 1 of the Meyer Reset included this rule for a time:

/* remember to define focus styles! */
 :focus {
 	outline: 0;

Sadly, not everyone did define focus styles, and Eric has removed this from v2.

Using a reset can also start to feel a little perverse. Resetting browser default styles does force us to deliberate on how each element should appear, helping ensure we use elements for their semantics and not their default styling. But for elements like i and em that’s almost always the browser default style. Other default browser styles, like the text sizes for headings which used to be ridiculously large, have changed to become passable defaults. There’s also the problem of someone wanting to use a reset HTML element after handoff, still with only the “unstyled” reset styles specified.

For me the main issue with resets is inheritance, leading to spam in your browser dev tools. When you’re trying to track down a CSS problem on a deeply nested element in someone else’s code, this does not help:

CSS reset rules repeating due to inheritance


Nicolas Gallagher and Jonathan Neal have taken a different approach with Normalize.css, “a small CSS file that provides better cross-browser consistency in the default styling of HTML elements”. As with CSS resets it gives us a reliable cross-browser starting point — the main reason for using a reset in the first place — but the two approaches are philosophically different.

CSS resets override user agent styles to return many elements back to an “unstyled” state, a level foundation we can safely build upon. However, we then need to define styles for most elements before we can build with them. Normalize.css instead addresses only the inconsistencies between user agent default styles, choosing the most appropriate default where there are differences. We get a safe cross-browser foundation here too, but one that includes normalized user agent styles as basic building materials ready for use. It’s basically a kind of an idealized, cross-browser version of CSS 2.1’s Default style sheet. For both ways we then need to add our own overriding styles to build the view, but because the browser defaults remain with Normalize.css, in general fewer styles need to be added.

Because the changes in Normalize.css are a lot more targeted, there isn’t an inheritance cascade of overwritten rules in your browser’s developer tools. Here’s a simple <ul>: “unstyled”, with the Meyer Reset, and with Normalize.css versions 1 and 2:

An “unstyled” unordered list element
Applying the Meyer Reset
Applying Normalize.css v1
Applying Normalize.css v2

You can clearly see the difference in philosophy, with the Meyer Reset example appearing as two lines of plain text with no margins, padding or bullets, while the Normalize.css examples are similar to the default styling. The difference in the styles applied to this <ul> are also easy to see.

However, these are not all the styles being applied to the <ul>. For comparison, here’s the same “unstyled” screenshot, but with the user agent styles visible, in Firefox 21 and Opera Next 15:

Mozilla user agent styles
Opera user agent styles

This is the CSS that we’re resetting or normalizing.

Normalize.css version 2 supports modern browsers plus IE 8, whereas version 1 also contains additional support for legacy browsers like IE 6 and 7. These older browsers need more normalization, and this can have minor disadvantages, for example the added vertical margins for the nested list in the Normalize.css v1 screenshot above. This split into two versions is useful if you no longer need to provide old browsers with Grade A support, and also if you want to learn about old browser quirks.

Normalize.css also helps correct some browser bugs, including “display settings for HTML5 elements, correcting font-size for preformatted text, SVG overflow in IE9, and many form-related bugs across browsers and operating systems”. For example, the following CSS fixes WebKit issues with HTML5’s new <input type="search"> element:

 * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
 *    (include `-moz` to future-proof).

 input[type="search"] {
 -webkit-appearance: textfield; /* 1 */
 -moz-box-sizing: content-box;
 -webkit-box-sizing: content-box; /* 2 */
 box-sizing: content-box;

Without it, WebKit’s default use of -webkit-appearance: searchfield; for type="search" prevents the styling of font, padding, border, and background properties on OS X and iOS, and gives buggy behavior for the border property on Windows.

An added bonus is Normalize.css is heavily commented and well-documented, helping you learn why each rule is there. This does make it noticeably longer than CSS resets, but when minified and Gzipped even the larger Normalize.css v1 is only 1KB.


While philosophically different to CSS resets like the Meyer Reset, Normalize.css is very much carrying on the same tradition, continuing in the footsteps of Tantek and Eric. You might even already be using it — it’s a core part of HTML5 Boilerplate, Bootstrap, and YUI’s new Pure.

User agent stylesheets are converging, and hopefully one day we won’t need to reset or normalize. There’s even a valid argument for not worrying about small differences between browsers (although being a Snook-level genius helps with that). But for now if you’re using a CSS reset, or nothing at all, give Normalize.css a try on your next project.


  1. [1] You can see the user agent style sheets for Mozilla, WebKit, and IE. CSS2.1 User Agent Style Sheet Defaults highlights the differences across (older) browsers. These styles also include things like style {display: none;} — try adding style {display: block;} to your CSS and see what happens.
  2. [2] Since then, all browsers have migrated to setting list indenting via padding-left or padding-start, with IE7 being the last IE browser to use margin-left for this.
  3. [3] For detailed background on the history of CSS resets, read The History of CSS Resets, by Michael Tuck.

My thanks to Eric Meyer and Nicolas Gallagher for their feedback on this article, and for these wonderful tools.

Postscript: While nuking margins and padding on all elements with * {margin: 0; padding: 0;} is gonna be a bad time, there is one universal selector-based reset you should still consider: * {box-sizing: border-box;}. This changes padding and border to being part of an element’s width, rather than additional to it. For more information, check out Paul Irish’s article “box-sizing: border-box FTW”.

Have a reason

Graphic design is an odd bird. It’s part art and part science, and often treated as mostly decorative. But armed with your favorite tools of the trade, it’s also very satisfying.

Teaching myself graphic design as a student, I created layouts based on what felt good. I was into that edgy, “creative” stuff. If you’ve got a great eye that may be enough, but now I also use this design golden rule: have a reason. Typography, grid-based layout, and basic design principles (balance, hierarchy, scale…) are essential foundations of great graphic design. Instead of throwing elements at a canvas and seeing what sticks, use these fundamentals to place them deliberately. Have a reason for every design decision. By doing so, you’ll increase resonance in a design.

In contrast, small differences (such as almost identical font sizes, or slightly unaligned objects) detract from this, often appearing as mistakes even if intentional. This gives me another rule: make differences obvious. If you’re going to break the rules (of your grid etc.), do so deliberately and make it count. Luckily, building a strong chorus of resonance in your design causes deliberate differences to stand out even more sharply.

Having a reason behind everything you do gives your work depth and subtlety. It shows you’ve thought carefully about each aspect, and lets you explain each decision.

Have a reason.

The name of things

Linguistic relativity is the idea that language influences the way people think — the names we use can have a powerful effect on how we perceive things.

If we’re thinking of [designing] a lunchbox we’d be really careful about not having the word “box” already give you a bunch of ideas that could be quite narrow. Because you think of a box as being square and like a cube. And so we’re quite careful with the words we use, because those can determine the path you go down.

Sir Jonathan Ive on “Blue Peter”

Horace Dediu points out that the names we use for the supercomputers we have with us are from a different time.

The first step is to stop adding the word ‘smart’ in front of phone. The second step is to stop adding the word ‘mobile’ in front of computer

Horace Dediu (@asymco)

I wonder what my kids will be calling these devices in ten years. For me “computer” already seems a term from an earlier time: the time before everything was a computer.

The labels we use in web design can also subtly affect our perception. For example, talking about web pages can lead us to perceive and design them as static comps with fixed dimensions, no different from print design.

Creating layouts on the web has to be different because there are no edges. There are no ‘pages’. We’ve made them up.

— “A Richer Canvas”, by Mark Boulton

What other names come to us with the mental baggage of past association? By considering their connotations, we can at least be more aware of their influence on us, and avoid the narrow, predetermined path of the obvious.

I recently moved, from Osaka to Tokyo. Packing your life into boxes is exhausting, but I found the “deciding what to keep” part reflective. I rediscovered some great books I’d bought and read years ago, but had not opened since. Revisiting Müller-Brockmann’s Grid Systems in Graphic Design again, I had fresh insights on how I could apply it to web design. Part of this was refreshing my memory, but there was more — I realised I’m a different person compared to when I read it the first time. At that stage I hadn’t designed to a baseline measure, and everything I’ve done since then (work, discussions, learning about Flexbox and CSS Grid Layout…) has affected my viewpoint.

I feel the same as the young me of 15 years ago, but my perspective has been continually changing. Realising this self-delusion is useful for judging my memories, and considering the viewpoints of others. Now I’m re-reading other “design thinking” books, to see what extra things the “now” me will perceive.

stack of design thinking books

Just like great movies, the best books and articles reveal more nuance the second or third time around. If you haven’t recently, re-read the best article of our profession — John Allsopp’s A Dao of Web Design, and reconsider this near-13 year old wisdom through the lens of Responsive Web Design and the zombie apocalypse of devices.

On Empathy

I ♡ our industry. Thanks to the blessing of View Source, the web has been egalitarian from the start — all we need are a computer, an internet connection, and the determination to learn. The lack of accreditation means we’re hired on the strength of our portfolio or GitHub account, and in general our industry feels like a meritocracy — do great work and you’ll be recognised for it.

I also feel despite the stereotypes that we’re on the whole a sociable and easy-going bunch, both online and In Real Life. We like attending the many conferences and meetups, and the leaders of our industry are amazingly approachable. Meeting others at events I feel a shared love for technology and making the world a better place, a wonderful “these are my people” feeling. I’d even go so far as to say that as a group we’re caring, of above average intelligence and attractiveness, and of course empathetic.

Well, I certainly considered myself to be empathetic. That is, until I discovered I’m not.

A fish in water

I realised this talking to my daughter about her teddy (bear with me…). She replied to “Come get him” with “You mean her”. I’d subconsciously perceived teddy bears as masculine, as if English words were gendered (like “L’ours en peluche”), but for my daughter the gender was naturally feminine. To think about this, it’s obvious. But for me this conversation was the difference between thinking and empathising. I use gender-neutral words with her now, like waiting for the “green person” to cross the road, and referring to toys as “they”, not “he” or “she”.

Coming to Japan was also an eye-opening experience for me. Along with the amazing experiences and wonderful people, many things I’d taken for granted or never even thought about are … different here. One that surprised me was how I reacted to being treated differently because I looked Western. Generally this attention has been positive — people making a fuss of me. But sometimes I just don’t feel like answering “Are you American?” again, or being complimented on my ability to use chopsticks. Sometimes I just want to be treated like everyone else. I soon learned those questions are just easy conversation starters for Japanese people not used to talking with foreigners. But even knowing that I still find this peculiar feeling of being “the other” can be unsettling, even when the attention is positive.

Empathy and us

Seeing things from someone else’s perspective is easy to intellectualise, but actually doing it is completely different, and considerably harder. People talk about walking a mile in someone else’s shoes, but few ever tie up the laces and do it. However, empathy is a core competency for us — we make things for people to use. If we don’t help the people using what we’ve made, we’ve failed, no matter how beautiful the design or elegant the code. This is incredibly obvious, but because we naturally assume other people are like us, it’s easy to think empathy without feeling it. We all have a self-image of being empathetic, and nobody says empathy is hard. But it is.

Luckily many of our best practices are exercises in empathy: user testing, personas, site visits, stakeholder interviews and even client meetings all provide valuable chances to see a project through other people’s eyes.

Level up in empathy

The easiest thing we can do to become more empathetic is to improve communication with clients, colleagues, and the people who will use our projects. It’s easy to assume motivations and guess at intentions — much of what we perceive is actually internally constructed, so listening to what is said (rather than hearing what we expect) can be surprisingly difficult. Frequent face-to-face communication helps, and building these relationships naturally makes us more empathetic.

When someone disagrees, try to avoid the temptation to “win the debate”, and instead focus on understanding what they believe, and why. A good test is how you react to criticism — treating it as potentially valuable feedback from a different perspective, and empathising with the person, helps to avoid taking it as an attack.

When you’re starting a new project, try to arrange time with someone who will use what you’re making, and if applicable consider volunteering to help them do that task for an hour or two. People are inventive and unpredictable, so you’ll probably discover some novel workflow, a feature that isn’t in the brief, or just a different perspective. Meeting people who’ll actually use what you produce is also a great help for frequent informal user testing and feedback later on.

More generally, try to get out of your comfort zone — learn new things unrelated to web development, talk to people from different walks of life, volunteer, travel somewhere you don’t speak the language. Although having kids might be a little extreme, using the web while holding a baby is a great insight into why usability is so important. Trying to use the web in a different language is also eye-opening, and has helped me realise the importance of copywriting, and consider how a non-native speaker might use what I make. Try ordering something on the Japanese Apple store, and see how far you can get!

Our self-image of (and job requirement for) empathy also makes recent online discussions of sexism in tech, with female beer pourers and all-male conference lineups, seem even more out-of-place to me. Reading @yesyouresexist is an amusing (and depressing) reminder of how unempathetic and self-deluded other people can be. But we are also “those people” on occasion, without even realising.

Luckily, knowledge is half the battle — just knowing that empathy is hard helps. As the year kicks off, let’s go beyond just “keeping the user in mind”, and aim for a more fundamental empathy with everyone involved. In addition to better working relationships, it’ll make our work noticeably better too.