A better application cache manifest

I’ve recently been messing around with offline application caching.  At a simple static level it is pretty basic, but once you start thinking about what might actually happen in real life it gets a lot more ugly.

The following sources got me started with offline caching in the first place.  If you need more background to what application cache is, you should read these first.

My main problem with it is that every time I make a change to my files, I have to go into my cache.manifest file and update a comment somewhere.  Why? Because the application cache is checked for updates first.  If there are no updates, it just stops.  It doesn’t check any of the underlying files for updates.

That’s efficient in terms of client-server communication by reducing the amount of calls to check whether cached versions can be used or need updated, but its also really dumb, and a nuisance to work with.  You start relying on people to remember on these little jobs, and that introduces a risk of human error.  It’s not an acceptable risk because it is an avoidable risk.

Luckily we can use server-side technology to generate our cache manifests and grab the file update timestamp.  Here’s what I’ve learned thus far:

  1. the manifest attribute on the html element doesn’t have to point to a *.manifest file.  It can point to a manifest.php file (for example).
  2. in the dynamic page, set your header to serve up the right mime type.  In PHP, this is
    <? php header("Content-Type: text/cache-manifest;charset=utf-8"); ?>
  3. find the most recently updated file date and echo it out in a comment. If there’s not been a change, the comment will remain the same in the generated code as it is in the cached version.   In my example below I’m statically setting which files I want to be in the cache. Jonathan Stark shows a way of going through the file system to cache all files if you’d rather.  You’d just add the timestamp bits in where required.
<?php
	header("Content-Type: text/cache-manifest;charset=utf-8");
	$cache_files = array(
					"testhtml5.htm",
					"testinvisdyn.php",
					"testhtml5.css",
					"testhtml5.js",
					"jquery.js",
					"json.js"
					);
	$fallback_files = array(
						"/" => "fallback/testhtml5fall.htm"
					   );
?>
CACHE MANIFEST
NETWORK:
*
CACHE:
<?php
	$cache_mod = 0;
	foreach($cache_files as $f){
		echo "$f \n";
		$last_mod = filemtime($f);
		if($last_mod > $cache_mod){
			$cache_mod = $last_mod;
		}
	}
	unset($f);
	
	echo "# $cache_mod \n";
?>

FALLBACK:
<?php
	$cache_mod = 0;
	foreach($fallback_files as $d => $f){
		echo "$d $f \n";
		$last_mod = filemtime($f);
		if($last_mod > $cache_mod){
			$cache_mod = $last_mod;
		}
	}
	unset($f);
	unset($d);
	
	echo "# $cache_mod \n";
?>

Disclaimer: I’m not a PHP developer, its not one of my professional competencies.  If the above code sucks, please respond in the comments and I’ll fix it up.

Interface Developer’s quality checklist

Towards the end of a project or sprint, time to delivery can sometimes get crushed due to any number of reasons (late wireframe or design delivery, too many iterations, staff illness, contractors leaving, underestimation, overdelivering, changing business needs, etc.), and sadly it is usually testing time that cops it.

This checklist should help you check you’ve got your main bases covered.

Tools you’ll need

Checklist

  1. Having stable, valid code will save you a lot of debugging pain.  If you know your code is sound, then it is most likely a browser fault that is the cause of any further bugs from here onwards
    1. Run the W3C HTML validator on all pages and correct
    2. Run the W3C CSS validator on all pages and correct
    3. Run the WAI tool on all pages.
    4. Run your JavaScript code through JSLint
    5. If you are hoping to have good coverage on mobiles, run mobileOK on your pages
  2. Check the static text content for spelling and grammar.  Mistakes here will just make you look stupid and unprofessional.
  3. Check you’ve done a full run-through of the site in each supported browser.  You do have an agreed browser matrix don’t you?
  4. View your site without CSS, can you still read everything?
  5. Open up each template in a new tab and run through them using CTRL+Tab to check your layouts are all the same – do the edges of the main layout boxes sit at the same position on each page or do they jump a few pixels? Is the main heading at the same position (presuming your design intends that)?
  6. Run through all pages at 1024×768 resolution (or 800×600 if you are required to support it), do you have to scroll horizontally?
  7. Try using your site without JavaScript.   If you can’t then non-JS users will not be able to use your site and search bots will not be able to index all your content
  8. Have you remembered your print stylesheet? Print preview your pages and actually print the most likely to be printed (e.g. an article template).  Sometimes the preview lies.
  9. If you are using flash, check your non-flash fall-back works.  You do have a fall-back right?
  10. If you are using embedded media, check there is a fall-back for those without it and a link to the vendor site to download the plugin.
  11. If you have static links in the site, run a linkchecker.  I’ve used Xenu in the past which is fairly good, and free.
  12. Run your pages through YSlow to find any major issues
  13. If you are using XMLHttpRequest (often referred to as AJAX), test what happens when the server returns a failure (e.g. a 404 or 500 rather than 200 OK)
  14. Accessibility checklist (this isn’t a definitive list, if for example your navigation is inconsistent between pages then you’ve a problem that requires the team going back to the drawing board to solve)
    1. Your content is in a sensible order in the HTML.  If you are not sure, looking at the page with CSS off will help you decide.
      • e.g. you do not break up your main content paragraphs to line up your right hand promo boxes
    2. Go through a few pages with a screenreader and keyboard.
      • Can you get to all your links and form fields without the mouse?
      • Can you hear all your content?
      • Is hidden content still ‘perceivable’?  If you are hiding with display none or visibility hidden, screenreaders will ignore that content, but if you use position absolute with left being a large negative number, it will still get read out to the user.
    3. Test all your interactive features (e.g. accordions or sliders) with a keyboard, also is the screenreader able to read the information in them? (see my previous post about focus)
    4. Page sections are marked out with headings
    5. Headings do not skip levels.  This should be picked up in the HTML validation.
    6. Have a ‘skip to content’ link at the top of your page
    7. You can pause any animation or movement that is on by default
    8. All forms have a submit button
      • that especially includes select field (dropdown) navigation, it should never be executed from the onchange or onselect events
    9. Text can be resized in all browsers, IE6 does it differently so be sure to test if you support it
    10. All form fields have explicit labels (i.e. you use the for attribute to refer to the field’s ID rather than wrapping the field inside the label element)
    11. Missing alt attributes is a common mistake, but will be picked up in your HTML validation
    12. Foreground and background colours have sufficient contrast
    13. Testing for seizure-causing animation is difficult, but the safest course of action is not to flash anything more than 3 times in 1 second.
    14. Image maps have their links duplicated underneath as a list
    15. Any static links have sensible link text that indicates where the link will go on its own without the rest of the paragraph text around it.
    16. Any linked images have sensible alt text that indicates on its own where the link will go
    17. Specify what language the page is in.  The HTML validator will pick it up if it is missing.
    18. Tables of data have a summary and scope for each column and each row is defined

Mobile web developments – a bit like the number 73 bus.

A number of interesting things related to mobile web have come up recently:

First, Phil Archer from the W3C presented Mobile Best Practice at London Web Standards Group

It’s an excellent presentation and worth a full read, but the gist of it is:

  • think about mobile users not mobile devices.  if nothing else, mobile devices are developing and improving their user experience as a fast rate which will probably get faster
  • you don’t have to give mobile users the exact same page only tiny, if you stick to the theme of your content you’ll be helping them (compare http://news.bbc.co.uk/ on PC and mobile, or try http://news.bbc.co.uk/mobile which BBC news redirects to) BUT don’t make them remember a special mobile URL.  Detect and redirect your user.
  • w3c have a very cool validator called mobileOK that estimates how well your page will perform on mobiles
  • secondary windows including popups, frames, tables and image maps will cause mobile users inconvenience
  • Progressive enhancement will pay off hugely
  • That said, various mobile browser vendors don’t play well with @media=”handheld”.  See http://www.bushidodesigns.net/blog/?p=72 for the best way to serve up CSS for all devices

Then Firefox announced accelerometer detection (the thing in your iphone/nokia/laptop/wii that detects motion and direction) for 3.6.  Firefox has yet to crack the mobile devices platform, so this is a signal of intent.

Serendipity then took me to PPK’s Great Webkit Comparison table whose family now includes the browsers for android, iphone, bolt, palm pre and possibly blackberry in the near future.

Get some focus: keyboard and mouse events

When we add interactivity, we use event handling.  A common trap is to handle the events that are fired by the mouse but forget about what non-mouse users need.

Click

Click events are obviously fired from the mouse clicking on an item, but they are also fired when the user is focussed on an element and presses enter, so click events are covered for keyboard users as long as they can tab onto them in the first place.

When you click on something, a focus event is fired as well as the click event, after all you are focussing on something when you click on it.  If you are listening for the focus event and attaching functionality to it firing, remember that this functionality will also occur when you click on the attached elements.

Mouseout/mouseover

Mouseout and mouseover events rely on a mouse to trigger them

For mouseout events, pair them with blur events

  • myelem.mouseout = function(){etc.}
    myelem.blur = myelem.mouseout;

For mouseover events, pair them with focus events but remember they will trigger on mouse click as well as mouseover

  • myelem.mouseover = function(){etc.}
    myelem.focus = myelem.mouseover;

See the code examples

(If you want to find out more about events, PPK has an excellent events write-up)

Get some focus: outline

When a link or button has focus, there is usually a visual indicator such as a dotted or coloured line around the element.

The CSS property is called outline.

Some designers/developers find the outline ugly and remove it using outline: none. Some reset CSS files also include this by default, with the optimistic expectation that you will set your own.

Eric Meyer says that he’s removed the outline “so that you remember to define your own”, however I’ve noticed that this is the exception rather than the rule.  I’ve a great deal of admiration for Eric Meyer, his work on CSS has improved many a developer including me, but on this issue I have to disagree.  A quick search on google code search shows just how regularly it doesn’t get done.

If you really wanted people to remember to redefine their own outline styles, you’d make it 6px solid red.

Removing the outline makes a page inaccessible because a keyboard-based user has no indication of what has focus or where their cursor is.  They have absolutely no idea of where they will end up if they press the enter key and absolutely no idea of where they are in the page order.

Visible focus in now an AA level accessibility guideline: http://tibor.w3.org/TR/WCAG20/#navigation-mechanisms 2.4.7

So please don’t remove the outline, and if you come across

a{
...
outline: 0;
...
}

in your CSS, remove this and set the outline to 0 on the hover and active states  or reset it using the :focus pseudo-class:

:focus {outline: 1px dotted;} /* or similar */

The colour of the outline should be inherited from the link’s default colour if you don’t specify one.

UPDATE: Patrick Lauke also has an interest in this and has set up his own CSS outlines test page. Suppressing the outline on the :active pseudoclass seems to be the most elegant solution to stay accessible while avoiding the outline for mouse users.

UPDATE 2: Patrick has since discovered a flash of outline occurs on links to external pages so the best suppression technique is:

a:hover, a:active { outline: none; }

Get some focus

When you click on or tab to an element, a ‘focus’ event is fired.  Focus has a significant role if we want to make sure our websites and especially our interactive features are accessible to everyone.

Focus is by default indicated visually either using an outline around the active element or by the flashing cursor for typed input areas.  This indicator may vary between browsers.

Chrome Browser showing focus

Chrome Browser shows focus by having a orange line around the link

Firefox link showing focus

Firefox shows focus by having a dotted line around the link

IE link showing focus

IE shows focus by having a black dotted line around the link

However, there are only 2 types of element that can receive focus through the keyboard.

  • anchor elements with href attribute
    • <a href=”#”>…</a>
  • form field, for example
    • <input type=”text” /> and other input elements
    • <textarea></textarea>
    • <select>…</select>
    • <button>…</button>

Wherever you need to have user-triggered interactivity, you need to use one of these focusable elements for the trigger.  I’ll cover this in greater depth in a later post.

About tabindex

Yes, you can force elements to receive focus by giving them a tabindex.   However, you then mess up the order in which elements receive focus.  Instead of following the order in which the HTML was developed, the focus will run through the tabindexed elements by numerical order, then go onto the non-tabindexed elements.  This might result in the cursor jumping around the page, which is especially annoying if the page is long enough to scroll.

Try the code example to test it out

Hello interweb!

I’ve been a full-time [web | client-side | interface | user interface | front-end] developer since I graduated in 1999, and I’ve set this up to post about web tech, interesting new developments and share the knowledge that I’ve accumulated and seem to keep repeating.

My particular interests are accessibility and also javascript, which can sometimes make for a challenging combination.