Tuesday, November 03, 2009

Some CSS Trickery Recorded For Posterity

Several mobile phonesImage via Wikipedia

I don't usually put development issues or code here, wanting this to be a space where I am not very technological, but I just needed to record this somewhere. It's about making websites that scale nicely from a full web page to a small handheld screen.

In an ideal world, part of the mobile strategy for a web property is that the design team thinks very carefully which parts of the functionality and user exeprience they want to preserve or highlight for mobile devices. Then they carefully categorize the classes of handheld devices it will be shown on, and write their mobile content to this categorization like Bryan Rieger illustrates, and configure the servers to sniff which browser is being used and redirect to the right content.

And sometimes you have 2.5 days to finish a brochure website and you need to slam something out for handhelds that just gets the information across. Which is the scenario I had to deal with a few weeks ago.

I am not talking about a complex website with user flows and shopping and profiles, but about the many many sites that basically have one center block of information per page, some navigation, and some secondary content. Looks great as a 3-column on the desktop browser, really should be transformed to a one-column site with simple navigation on something small. Which can be really easily done using standard W3C style-sheet CSS technology: make one for the desktop that is all beautiful, and one for handhelds that switches most content to be invisible and the navigation to be simple, and set the right switches in the header to tell the desktop browsers to load the desktop style sheet and the handheld browsers to load the handheld style sheet.

Except, of course, from the moment the technology was specified, handheld makers were subverting it by basically ignoring the handheld directive on their flagship phones, telling their handheld devices to ignore the handheld CSS and always load the desktop one, basically claiming their scaling technology for every site was better than what a webdesigner taking the time to carefully create a handheld CSS for a specific site could come up with. Browsers with delusions of grandeur, like non-touch Symbian devices and Blackberries, all with screens no taller than 400 pixels.

Dean Hamack over at Bushido Designs details the sad state of how handheld browsers are all very different and not listening to standards, and the bullet-proof trickery he uses to make desktops and handhelds load the appropriate style sheet, using careful cascading of imports and media directives. But in the comments he points to having found a simpler way, and after having done some of my own experiments I concur: just using JavaScript in the header is the way to go.

This was not how it was supposed to be, and the usual recommendation is not to use JavaScript for something as vital as overall lay-out, as JavaScript can be flaky or never have been implemented or switched off. But I think this thinking may be outmoded, as the JavaScript in question is very simple, a good alternative is available if there is no JavaScript, and the most problematic browsers -- the ones on handhelds with delusions of grandeur -- have, as part of their delusion, JavaScript implemented and switched on by default. Well, we should take advantage of that.

So my current stack of CSS includes in a page header looks like this:
<noscript>
<link rel="stylesheet" type="text/css" href="handheld.css" media="handheld">
<link rel="stylesheet" type="text/css" href="desktop.css" media="screen">
</noscript>
<script language="javascript" type="text/javascript">
if(screen.height > 320) {
document.write('<link rel="stylesheet" type="text/css" href="desktop.css" media="Screen" />');
} else {
document.write('<link rel="stylesheet" type="text/css" href="handheld.css" />');
}
</script>
<link rel="stylesheet" type="text/css" href="iphone.css" media="only screen and (max-device-width: 480px)">
<link rel="stylesheet" type="text/css" href="print.css" media="print">
<!--[if IE 6]>
<link rel="stylesheet" href="ie6.css" type="text/css">
<![endif]-->


I start off with directives in case JavaScript is switched off or not implemented ("<noscript>"), in this case we are most likely dealing with a desktop browser run by a purist or a handheld that knows just fine it is a handheld and didn't even try to run JavaScript, and the media selectors in both directives will be honored properly. A designer might even take the opportunity to make a desktop CSS that shows an alternate display of any items that depend on JavaScript working. We could also be dealing here with a handheld with delusions of grandeur of which the owner has switched JavaScript to off, and then we are back to square one, and I am hoping this is a very seldom case.

Then comes JavaScript that basically checks how big the screen is and then loads the appropriate style sheet. This can be as complex as you want, covering every eventuality of screen shape. I just went for forcing a handheld style sheet on devices that simply have too small a screen to pretend they should be ignoring the handheld media directive and will otherwise load the desktop one -- I am looking at you Nokia E71; you are a wonderful handheld device but you have no business ignoring a handheld CSS if it is available, which you do, and really shouldn't.

A designer could even design to set the cut-off to a larger device, like 480 pixels of height, forcing this stylesheet on iPhones and Android devices as well, but I am finding the machines that run these operating systems run and show and scale and zoom simple desktop sites just fine, so I am willing to let them try. Although, in the next line I do use a CSS media directive to load an iPhone and Android specific style-sheet, because I recently found that WebKit on those phones have different behavior from WebKit on the desktop and that sometimes needs to be compensated for.

And then of course, a print style sheet, and some trickery for a style sheet to be loaded only on Internet Explorer 6. That browser we are never getting rid off, so we will always have to deal with those bugs. I prefer to isolate them in a sheet of their own.

No, I haven't exhaustively tested this on every Blackberry and Nokia and handheld and OS possible. But I think I am covering a lot here just fine.