I currently have limited availability - please get in touch if you'd like to work with me.

Building for the device agnostic web

Orde Saunders' avatar by Orde Saunders

"Agnostic" is a big word - what does it mean? It's faux Greek for "not knowing".

So what is the "device agnostic web"? It means we don't know what device will be used to interact with our site.

But isn't that just "The Web", right? No. There are plenty of people out there who try to control which browsers interact with their sites:

WTF Mobile Web

This is a whole load of fails concentrated in one place. The Carphone Warehouse aren't a warehouse and they don't sell carphones. They sell mobile phones and this is the product page for pretty much any mobile phone when viewed on a mobile phone.

How bad is this problem?

"45% of the Fortune 100 target smartphone users with dedicated mobile sites today, yet none of the companies studied fully comply with Google's mobile site requirements."

http://www.prweb.com/releases/PureOxygenLabs/MobileSEOAssessment/prweb10866624.htm 2013-06-25

Nearly half of the top 100 American companies are trying this and none of them are getting it right as judged by Google's mobile site requirements. These guidelines aren't exactly rocket surgery - they basically say "don't break the web" and yet people still can't manage it.

It's not just mobile phones

  • Tablets
  • Games consoles
  • Televisions
  • Screen readers
  • Search engine spiders
  • The future: ???

This problem is probably highest profile with mobile phones but there are an awful lot of things out there that are interacting with web sites.

We've got tablets, games consoles, smart televisions, screen readers, search engine spiders - and they vary greatly in capabilities.

We're in the present - we're trapped between the past and the future. We need to build sites that will work in browsers from the past and browsers from the future.

How do we deal with this?

Progressive enhancement. We start with a solid foundation and enhance from there.

Elements of a web page

  1. HTML(Content)
  2. CSS (Presentation)
  3. JavaScript (Behaviour)

The traditional view of progressive enhancement is that you start with the HTML for the content, add CSS for the presentation and finally add on JavaScript for the behavior.

This separation of concerns should, of course, be the the foundation for any site but we can do more: We can also apply progressive enhancement within each of these elements.


  • Clean
  • Semantic

The core attributes of our HTML are that it should be clean and semantic. Getting this right gives us the best chance of it working everywhere.

Let's look at these attributes in a bit more detail:


  • Correctly nest tags
  • Close all tags (e.g. <br/>)
  • Quote attributes
  • Well formed XML

Previously I would have said 'valid' rather than 'clean' here, however, HTML 5's validation rules are lax enough that it's not much use as a guide for where we need to be.

What we're looking for is robust markup that's not going to cause problems for any browser's parser.

An advantage of HTML5 is that progressive enhancement is built it - browsers will ignore things they don't understand. This means that, providing we get the basics right, we can safely use more modern markup as long as we don't rely on it.

Correctly nesting tags should be something you are doing anyway - whilst you might be able to get away with overlapping tags in some browsers, you don't know how reliably an unknown browser will react.

Close all tags - even those you don't strictly have to like line breaks, meta tags and other singleton tags. Yes, you can get away with not doing it but if you do it you don't have to "get away with it" - it's just going to work.

The same goes for quoting attributes - if you quote them, it's going to work.

What we're building up to here is that your HTML should be well formed XML. Now that probably sounds like overkill especially as nobody really likes XML that much. The point here is that if it's well formed XML then the browser's parser doesn't have to guess about anything when it's building the DOM tree, you're not going to be caught out by how an unknown browser handles HTML it doesn't fully understand.


  • Headings
  • Paragraphs
  • Lists
  • Anchors
  • New HTML5 elements

I'm not going to get into the details of exactly what element should be used to markup what content, that would take forever, everyone would disagree with me and we'd all be right.

However, headings, paragraphs, lists and anchors have been around since the start of HTML. If you make sure your content is correctly marked up using these then it really should work in any browser ever made.

The new HTML5 elements - and in particular the sectioning elements such as header, footer and the like - are fine to use but don't rely on them. The definitions aren't all stable and I'm not sure if there's really much out there that actually uses them.

The other thing to bear in mind is that older browsers - and not just IE - might not recognise them. My recommendation is to put them in to mark sections but then put divs inside them to actually hang styles and functionality from. See: HTML5 Elements for Legacy Browsers

Try not to get analysis paralysis with figuring out the correct way to semantically markup content. Start with the basics to give you a good foundation and think about what the content is supposed to be rather than how it is supposed to look. Making a few dodgy decisions here and there is much better than not even attempting it.

If you can change the layout of your site purely by changing the CSS and not touching the markup then it's a good indication that it's semantic.


  • Baseline presentation
  • Media queries
  • Interaction optimisations

Like HTML, CSS has progressive enhancement built in - browsers will ignore things they don't understand. Again, providing we get the basics right, we can use advanced features provided we don't rely on them.

Baseline presentation

  • Colours, typography, backgrounds, borders, etc.
  • Linear layout - no floats.
  • Basic interactions - no hover.

Your baseline presentation is the core elements of the CSS. It should contain the basic style elements of your site such as the colours, typography, backgrounds, borders and the like.

The baseline layout should be completely linear with everything 100% width. Don't use any floats at this stage as some legacy browsers don't handle floats and other layout styles very reliably.

Don't add any interaction enhancements at this point - specifically no hovers.

The site's not going to look very inspiring at this point, it's just one long list of branded content - not much different to the unstyled HTML. However, this is exactly what we want - it's a baseline presentation that any browser with CSS support will be able to handle.

Media Queries

  • Layout solution
  • Media query support: @media only all
  • Not just width

It's important to remember that media queries and responsive design are not a silver bullet to cross device compatibility. They are a layout solution.

We can detect for media query support with @media only all.

This is essentially our "cutting the mustard" test for good CSS support so, as we have a reliable baseline, we can start applying layout CSS and be fairly confident that it will be supported.

Don't forget that there are more media queries than just width. For example height can be very useful to compress vertical whitespace for small screens in landscape orientation - such as Google Glass.

Interaction optimisations

  1. Sequential (keyboard)
  2. Direct (touch)
  3. Location aware (hover)
  4. Ambient / Passive (sensors)

There is a hierarchy of interactions. Sequential navigation where you move from one item to the next in sequence is the baseline, this is normally keyboard navigation but that also includes things like game controllers. The key to sequential interaction is keeping the user informed of where the current focus of interaction is.

Direct interaction uses the same interaction points as sequential but in this case they will be activated in isolation. This is exemplified by touch interactions and is probably the easiest and mode of interaction to deal with.

Location aware interactions know where the point of interaction is before it is activated. The mouse is the main example of this and it allows us to use hover states. However, as this is further up the hierarchy you can't use this to present information not available to sequential and direct interactions.

At the bottom of the hierarchy we have ambient or passive interactions such as information from sensors such as location and network. This is still a very new area and should be used with caution as they don't express a conscious desire for interaction.


Progressively enhanced CSS

For more information about this see my article on progressively enhanced CSS


  • No JavaScript
  • Feature detection
  • Cutting the mustard

Whilst JavaScript used to be used to provide small dynamic enhancements it's increasingly used to provide core functionality. Unlike HTML and CSS, JavaScript is not fault tolerant. If you include something in JavaScript that the browser does not understand it will come to a stop. This means we need more robust techniques for enhancement.

No JavaScript

  • Core content is accessible
  • Use JS to add a CSS hook
  • Use CSS hook to set initial presentation for enhanced functionality

Whilst it's easy to assume that JavaScript is everywhere these days, JavaScript support varies significantly between browsers and, as we did with HTML and CSS, we're going to be starting with a safe baseline and enhancing. With JavaScript the safest baseline is when it's not present.

You don't have to have all your functionality replicated when JavaScript is disabled but your core content and any functionality required to access that should be available.

Before you declare any CSS in your page use some inline JavaScript to add a class to the HTML element. This is really simple and can be done in one line. Once you have the CSS hook you can then set the initial presentation for enhanced functionality - such as hiding everything in an expandable menu.

What you should be aiming for is being able to complete the basics - for example adding a product to a shopping cart and then checking out. This is going to be a lot more clunky than with JavaScript enabled and there's no reason to spend too much time optimising this. Now, when (not if) when JavaScript breaks or otherwise isn't available, your users are still able to use your site.


Feature Detection

  • Enhance functionality using feature if present
  • Polyfill missing feature
  • Fall back on non JavaScript functionality

Whilst browsers will ignore HTML or CSS they don't recognise, if you try to use JavaScript they don't recognise they'll throw an error. To avoid this we need to detect if a feature is supported before using it.

The basic formulation for feature detection is to check for the presence of the feature in it's container - frequently document or window. There are exceptions and it's different for HTML features but the idea is the same - you are detecting whether the feature you want to use is supported in the browser.

If you know the feature is supported you can then enhance using that feature. If the feature isn't supported then you can either pollyfill to emulate the missing feature or fall back to the non JavaScript functionality.

Pollyfilling functionality is tempting so it's very easy to end up with a lot of code doing this. This code can be hard to maintain and test so, for each pollyfill, you should thoroughly examine if the feature you want to use really is important enough to warrant that investment of time.

So if we're not pollyfilling this missing JavaScript functionality what are we going to do? Because we have started with a baseline that core functionality is available without JavaScript we don't have to do anything - the cor

Cutting the mustard

  • Feature detect a minimum level of support for enhancements
  • Only request JavaScript when supported
  • Fall back on non JavaScript functionality

"Cutting the mustard" is a term coined by the BBC responsive team. The principle here is that you feature detect for a set of minimum requirements and only request and load the JavaScript when these requirements are met. This has two advantages:

  • We can use more advanced JavaScript features knowing that they will be supported.
  • Devices that won't run our JavaScript won't even waste time downloading it.

This is a really useful technique for dealing with older browsers that have limited JavaScript support, it means you're not having to deal with a lot of compatibility problems and, because your core functionality works without JavaScript, users of these older browsers aren't missing out.


Non JavaScript functionality

The common perception of providing non JavaScript functionality is that it's for people who have JavaScript disabled in their browsers and there aren't many of them so why bother?

As we've seen, having your core functionality available without JavaScript is important for more practical reasons: It enables your users to continue to use your site when something is broken, or missing either by accident or design.

Paradoxically, by providing support when JavaScript isn't present it allows you to provide better support when it is present.


People often think of accessibility as being for the disabled but, done right, it will make your site more accessible for all your users regardless of ability, device and conditions.

Accessibility can seem daunting but if you get the basics right throughout the process then it doesn't have to be a big thing. Accessibility only really becomes a problem when you try and retro-fit it to a project at the end.

Accessibility (structure)

  • Image alt attributes
  • Form labels
  • Tab index
  • ARIA roles

We already have semantic markup and that's a brilliant foundation but there are a few more things that, if you get them right in your markup, will enhance your site's usability for all users - not just those that rely on assistive technology.

  • Images must have an alt attribute, even if that is null.
  • Form inputs must have labels. Some controls - like buttons - are implicity labelled but text boxes, radio buttons, checkboxes and the like need labels.
  • Use the tabindex attribute to make sure that all your controls are accessible by keyboard navigation in a logical fashion. We'll come on to keyboard navigation later but it's not just for keyboards - the D-pad on game console controllers is normally mapped to this. You can actually do quite a bit with the tabindex attribute so I suggest you look at the documentation.
  • ARIA roles have the promise to give a significant boost to assistive technologies but unfortunately it seems support for them in assistive technologies is slow in arriving. It's definitely worth finding out about them and putting them into your code but don't rely on them.

Accessibility (presentation)

  • Contrast - 4.5:1
  • Focus highlight
  • Fixed dimensions in em

As with HTML, accessibility in CSS isn't just for disabled users. An accessible site will be easier for all users to use.

Designers: If you only remember one thing from this talk then remember this: The minimum accessible contrast ratio between foreground and background is 4.5:1.

Don't think of this as a restriction, treat it as a challenge. The best designers I've worked with have come up with some really creative solutions that are right on this limit. And don't forget: this contrast isn't just for blind people, it will make your site easy to read on monochrome screens, small screens, screens in sunlight, screens viewed at an angle - in fact most situations that aren't the nice big screen in ideal lighting you use to do your design work.

Set a prominent focus highlight. This is essential for keyboard navigation. This doesn't look the best for mouse and touchscreen navigation but you can use JavaScript to remove this until you detect keyboard input - the important thing is to have a prominent highlight by default.

Don't use pixels for fixed dimensions - use ems. This allows users to change the base or minimum font sizes and your site won't fall apart.



  1. Set a performance budget
  2. Use objective measurements (not times)
  3. Defer non-essential items (e.g. analytics)
  4. Validate using real user monitoring (RUM)

There are plenty of studies that show that the faster your site is the more people will engage with it. Speed is also a factor in Google rankings and, thanks to a server configuration issue, I've seen that in action.

You should set a performance budget for your site to prevent it getting too slow as you add more without taking anything away. Sticking to a budget means that when you want to add something new you have to take something out and that forces you to think about how much value the new feature really adds.

Whilst it's tempting to think of your budget in terms of time - after all that's what performance is all about - it's not practical to accurately measure time when you are building a site. You need to define your budget in objective measurements that contribute the page speed. The key metrics you should be focusing on are:

  • Number of HTTP requests
  • Total page weight
  • Percentage of visual rendering complete (speed index)

You can make some space in your budget by deferring non-essential items. And by essential I mean essential to your users. Analytics is a classic example of this - whilst you might conciser them essential, your users don't care. When was the last time you saw a slow website and thought: "I'm happy to wait for this if it means they get good analytics."

Whilst I did say don't set your budget using a time measurement, it's a good idea to measure how fast pages are actually loading for your users - this is known as real user monitoring. With enough data you can get a meaningful average and you can use this to ensure that changes you make to the site aren't having a negative effect on your users' load times.


  • Test using real devices (devicelab.org)
  • Focus your testing
  • Use Opera Mini

Building sites this way may sound like you have to do more testing, in fact it should reduce the amount of testing as you should be testing in multiple devices anyway but, if you build it right, more things should just work so that means less defects and less work fixing them.

Emulators are OK but there's no substitute for testing using real devices. There's nothing quite like an entry level smart phone to highlight issues with performance and usability that you'll will be covered up by a top of the range device.

You should focus your testing. There's not really much to be gained by doing a full regression on every device and in every browser. You should think about what could cause a problem and focus on those areas in browsers you know will expose that.

The single best browser for testing is Opera Mini. Due to the way everything is rendered on the server side and sent as a static page to the device it will really test how robustly your site is built. If you site works well in Opera Mini you're probably not going to have any major problems anywhere else.

In Edinburgh we have a world class facility in the Device Lab and I recommend you go book some time for testing - they've got everything set up including a number of tools that make testing on a multiple devices much quicker and easier.

I'd also suggest booking some time to do some research, take your team down there and have a look at your site, your competitors' sites and other sites from outside your industry. Look at what's working and what's not and use that to inform which direction you take your site.

The future

What's going to happen in the future?

Learn from the past.

Code you wrote in the past is now living in the future. Look at how that's working in new browsers.

  • What did you do that worked? Do more of that!
  • What did you do that broke? Don't do that again.

Browsers are very good at dealing with old websites, if you've built your site to be compatible with older browsers then it's a safe bet that new browsers will be able to handle it.

Be general, not specific

The more general you make your code the less likely it is to cause you problems. If your code targets specific browsers then when those browsers change you have to change your code in order to prevent it breaking.

When Google announced Blink and Mozilla announced their Servo rendering engines on the same day this was my reaction:

If you have to change your site when Apple release a new version of one of their products: you are doing it wrong.

Give up control (You never had it anyway)

One of the keys to building in a device agnostic manner is to give up control: You never really had it anyway - you just thought you did.

Whether trying to deliver the same pixel perfect site to every user or delivering reduced functionality to mobile users 'on the go', trying to exert a control we don't have over how our sites are viewed is fighting a losing battle.

I know it can seem a bit scary but once you accept that you don't have control over how your users interact with your site it's actually very liberating - you've got no choice but to get the fundamentals right and, once they're right, you have a lot more freedom with how you build up from there.

Future Friendly

  1. Acknowledge and embrace unpredictability.
  2. Think and behave in a future-friendly way.
  3. Help others do the same.

Future Friendly is a philosophy that emerged as a positive reaction to the increasing varieties of devices that can be connected in the web.

It acknowledges that the only predictable thing about the future of the web is that it will be unpredictable.

By building in a device agnostic manner we embrace this unpredictability.


View the slides for Building for the device agnostic web