Vertical alignment of child and parent

Which are the blog entries I will enjoy looking back on most in ten years’ time: the hard-core techie ramblings about irrelevant ancient technical obscurities, or the personal musings that give insight into where my heart was at?

Thought so.

I don’t remember when I got to be as tall as my mum, but Alex is getting pretty close now. This photo is from last week (21 March 2012). Alex will be 11 in just a couple of weeks.

Outdenting properties for debug CSS

Whenever I’m tinkering with CSS for experimental or debugging purposes, I usually end up adding a ton of properties to help me figure out how things fit together: weird background colours, borders, alternate fonts, etc. I don’t want to leave these properties in place when I put the CSS live, though. To mark a CSS property as a temporary/debug property, I outdent it, putting it at column 0 in the file:

.monkey{
    position:absolute;
    height:200px;
    width:300px;
    top:20px;
    left:20px;
    background:url(/images/monkey.jpg) no-repeat;
border:2px solid green;
    z-index:10;
}

If you diff your code and review your changes before you commit to your version control system (you do use a VCS, don’t you?), it’s often easy enough to spot a debug property, and fix it before you actually check it in. But sometimes the changes are subtle, and they slip through anyway. By outdenting properties, they remain visually obvious in your code even after accidentally pushing them to production.

Sometimes adding a property isn’t the right debugging technique. Sometimes you want to override a property instead — and set yourself a reminder to change it back when you’re done. Because later property values overrides earlier ones, this technique works just as well:

.fez{
    position:absolute;
    height:200px;
    width:300px;
    top:20px;
top:100px;
    left:20px;
    background:url(/images/fez.jpg) no-repeat;
    z-index:10;
}

You can do the same by commenting out the original property, of course, but I find the outdenting technique faster to clean up afterwards.

Goldilocks and the Three Device Pixel Ratios

By default, your typical mobile browser (Mobile Safari, Android browser) will pretend to have a “desktop-sized” viewport when it renders a web page. The web page will appear zoomed-out and tiny, and you’ll have to zoom in to read most of the text. The photo below shows three Android devices side-by-side, rendering a plain web page, so you can compare what they look like. From left to right, the devices are:

  1. Samsung Galaxy Y running Android 2.3. Screen size: 240px x 320px; physically 4.5cm x 6cm (~135 pixels/inch)
  2. Samsung Galaxy Ace running Android 2.2. Screen size: 320px x 480px; physically 4.9cm x 7.8cm (~166 pixels/inch)
  3. Motorola Defy+ running Android 2.3. Screen size: 480px x 854px; physically 4.5cm x 8.1cm (~271 pixels/inch)

As expected, the page is zoomed out, and the JavaScript I use to read the screen width reports 800px.

If you are building for mobile, you probably don’t want this. You can use the viewport meta tag in the head of your document to tell the browser to render at the actual width of the device.

<meta name="viewport" content="width=device-width">

The photo below shows the Android browser rendering a page with this meta tag:

Wait, what? They all show a screen width of 320px? Don’t those three devices all have different screen sizes? Shouldn’t they go 240px, 320px, 480px? I paid for a high-resolution 480x854px phone, damn it; where are my pixels?!

Let’s have a look in Opera Mobile:

240px, 320px, 320px. O-kaaaay…

What’s going on is that the device/browser manufacturers are trying to be helpful. The screen of the Defy+ phone is physically narrower than the Galaxy Ace, but it squeezes more pixels into each square inch of the display. Using one device pixel for each CSS pixel of a 480px-wide layout on a 4.5cm-wide screen would result in some very small text. So there is a zoom factor to adjust the way the page is rendered. In Opera Mobile, you can see (and change) the zoom factor by going to Settings → Zoom. The picture below shows the zoom zettings on these three phones:

You can see that on the third device, the zoom level is set to 150%, which is how 480px gets turned into 320px. If I set that to 100%, then the results are as expected:

The stock Android browser has a similar setting, found under Menu → More → Settings → Default zoom. In the Android browser your choices are limited to “Close”, “Medium”, and “Far”.

By default, all of the Android browsers had their zoom set to “Medium”. By setting the first device to “Close”, and the third device to “Far”, I can persuade the devices to render at their natural hardware resolution.

This doesn’t actually help me as a web developer, though, because I can’t force a user to change their browser settings.

This is where the target-densitydpi=device-dpi viewport setting comes in. With this setting, you can indicate that you want a specific page to render at the device’s native hardware resolution:

<meta name="viewport" content="width=device-width, target-densitydpi=device-dpi">

If I set all the android browsers back to the default “Medium” zoom, and set the zoom on Opera Mobile back to 150% for the Defy+, then I get the following results when I view a page with the target-densityspi property set:

Looking back at all these photos, you can see that the test pages show a second value, pixel ratio, which comes from window.devicePixelRatio. This should (I think) tell you how many device pixels go into a CSS pixel. For example, if the screen width is 320px, and window.devicePixelRatio reports 1.5, then the device is actually using 480 hardware pixels to render the 320px-wide layout. This means you’re working with a high-resolution display, so text will be crisper, and you can use high-resolution versions of images.

But although this works as expected in Opera Mobile, the Android browser seems to always report the default value for window.devicePixelRatio no matter what the actual value is on the page, as specified either by the user’s zoom setting, or forced by the target-densitydpi=device-dpi property in the viewport meta tag. Android browser on the Defy+ keeps reporting a value of 1.5 even when it is using a 1:1 pixel mapping, and the Galaxy Y keeps reporting 0.75. Likewise, min-device-pixel-ratio media queries are triggered from these default values, not from the active pixel ratios. This might be a problem when it comes to loading different versions of image assets.

I don’t recommend using this target-densitydpi viewport setting in real life. It may be tempting to force a 1:1 pixel mapping so that you can deliver wider layouts to high-resolution devices, but a typical 480px-wide layout looks uncomfortably small on a 4.5cm-wide screen. The point of high-resolution screens on mobile devices is to make the content look sharper at the same physical dimensions, not to keep squeezing more and more content into that space. I’m pretty sure that’s why Mobile Safari on iOS does not support this property in the viewport meta tag at all.

At the other end of the scale, there are plenty of low-resolution devices out there that use a devicePixelRatio of less than 1 to make their small viewports appear wider. The inexpensive Samsung Galaxy Y is a great example. It has a screen width of 240px, but pretends to be 320px wide by rendering 4 CSS pixels are across every 3 hardware pixels. This makes 320px-wide layouts look a bit blurry, but that’s better than breaking; many sites consider 320px as their mobile baseline (hello, iPhone), and ignore smaller viewports.

(Aside: “Nobody really uses a 240×320 screen” is the 2012 version of “nobody really browses the web on their phone.” Actually, yes they do. But because of this pixel scale factor, you might not notice them in your analytics.)

Basically, don’t set target-densitydpi unless you really know what you’re doing, and are prepared to consider the actual physical dimensions of your CSS pixels, which means testing on a lot of devices. Otherwise, trust the mobile browser to render those CSS pixels at a size that is comfortable for most users. If the user wants more control, the browser zoom setting is just a couple of taps away.

Test pages

Further reading

Devices, devices, devices

Before I start on my own thing, let me first point you to what Brad Frost and Stephanie Rieger have already written on the subject of building a device library:

Without wanting to get into the debate over “sites” and “apps”, I think the distinction has some bearing on how you choose to spend your money in building a device library. Here’s how:

  • Site-like, or document-oriented web projects generally align with a 100% compatibility strategy: you want your content to render acceptably and be at least minimally usable on any web browser.
  • App-like web projects generally align with a partial compatibility strategy: your focus is on providing a set of features to browsers that meet a set of minimum requirements. (Although if your requirement is simply “webkit”, I may have to come and hurt you.)

Other markets are different, but StatCounter’s mobile figures for Europe in February 2012 show that 73% of mobile browsing comes from iOS and Android devices. (Some Android and iOS users may be using Opera Mobile or Mini, but that percentage is small.) Throw in a smattering of BlackBerry 6 and 7 devices, some high-end Nokias, and a few Windows Phones, and you could take this to mean that about 80% of mobile web users are working with a touch-screen device running a relatively modern browser.

If you go with the partial compatibility strategy, your device library should cover this 80%. Testing a feature-heavy site on BlackBerry 5 or Nokia S60 browser is going to drive you mad, and isn’t going to serve your core customer base. Because you’re concentrating on the medium-to-high end of the market you’ll spend more money per device, but you can get away with relatively few of them. I’d suggest a handful of Android and iOS devices, a BlackBerry 7, and a Windows Phone Mango. Make sure that the devices you get cover a variety of screen resolutions (small smartphone, large smartphone, tablet).

If you’re aiming for 100% compatibility, you need to focus your attention on the other 20%, because that’s where you’re going to spending the vast majority of your time debugging and fixing crazy bugs. Buy as many cheap, old, low-spec, oddball devices as you can lay your hands on. Any time someone says “WTF – you’re browsing the web on that thing?” award yourself special bonus points. Low-spec is good because if your site works well on a slow device, it’s only going to do better on a faster one. Because the 20% represents the long tail, you will need more devices, but they will be cheaper ones, so you’ll probably end up spending just the same amount of money.

Building a device library is not a one-off thing. It’s not like a developer workstation that you can get away with upgrading every 2-3 years. New devices and new OS upgrades are being delivered at a rapid pace. If you can afford it, you should be looking to add new devices to your library at least every six months. Again, if you can afford it, don’t upgrade the OS on old devices. Over time, they will become your legacy devices.

Finally, I consider it important to actually use the devices. Having a spectrum of devices sitting on a shelf in the office while you walk around with an iPhone 4S in your pocket will not get you exposed to the strengths and weaknesses of the different platforms and form factors. For example, if all you use is a touchscreen, you won’t understand what it’s like to browse with just a keyboard. (Try unplugging the mouse from your desktop machine, and see how that works out.)

For reference, here’s the stack of devices I have on hand for testing:

  • Nokia N95. 240×320 screen, S60 browser. The first phone I used for doing mobile web work. Released in 2007; an impressive piece of kit at the time. Unfortunately it has lost the ability to connect to my wifi, so testing with it is a bit of a pain now.
  • Nokia C3-00. 320×240, keyboard, no touch screen. Uses the Nokia Ovi browser by default, but also has Opera Mini built in. Cute little phone.
  • Nokia C5-03. 360×640 resistive touch screen with haptic feedback – it buzzes when you press the screen hard enough for it to register a touch/tap. The screen is small, but high resolution, and looks great. I used to think that it was a bit crap for web use because it only had a numeric keypad, but that was before I figured out that the qwerty keypad only shows up when you hold the phone in landscape mode on its left side, not on its right. Way to go, Nokia. Also, the “Create WLAN connection in offline mode” prompt should have died 5 years ago.
  • Motorola FlipOut. Android 2.1, 320×240 touch screen, and a keyboard. The keyboard doesn’t slide out, it rotates out from behind a corner. When it’s closed, this looks more like a pager than a phone. It’s cute and small, and I really like it.
  • Samsung Galaxy Ace. Android 2.2, 320×480 touch screen. Relatively cheap and versatile, because it can be upgraded to run 2.3 as well. (Buy two while they’re still selling them with 2.2!).
  • Samsung Galaxy Y. Android 2.3, 240×320 touch screen that pretends it’s 320×480. Cheap. Nice-looking little phone, but the touch screen is dreadfully inaccurate.
  • Acer Iconia Tab A100. Android 3.2, 1024×600. Piece. Of. Crap. Poor screen, slow, a capacitative “home” button that makes an accidental touch target no matter which way you hold it, and the battery won’t hold a charge in standby mode for more than 48 hours. The only thing it has going for it is its price. (That, and the fact that it fills the Android 3.x hole in my line-up.)
  • iPhone 3G. iOS 4.2, 320×480. The first iPhone in our household; I inherited it from Abi when she upgraded to a 4 in 2010. Useful as a legacy iOS4 device.
  • iPod touch 4th generation. iOS 4.3, 320×480 (retina). Gorgeous little device. This is my stand-in for an iPhone 4, because it has the same A4 chip and retina display resolution (although the screen is slightly lower-quality than the actual iPhone 4). I’m currently trying to figure out if I want to upgrade it to iOS5 to match the distribution of hardware in the wild, or keep it on iOS4 as a legacy device. It’s a cost consideration.
  • iPad (original). iOS 5, 1024×768. Still great.
  • BlackBerry Curve 8900. BlackBerry OS 5, 480×360 screen, keyboard. BlackBerry 5 is the OS That Will Not Die. BB5 devices are still being sold in volume because they’re cheap, have great keyboards, and people like using them for texting and messaging.
  • LG Optimus 7. Windows Phone 7 Mango, 480×800 touch screen. This was my first Windows Phone, but I don’t think it’ll be my last. I like WP7 as an OS. I like the sleek design, and the live tiles on the home screen. As a phone, the Optimus 7 is just okay. It’s big, heavy, the screen brightness is harsh, and the camera is only so-so. But I still found myself carrying it around a lot as my day-to-day phone.
  • Nintendo 3DS. This is what I mean by “oddball”. It has two screens, one on top of the other. The top screen has an effective resolution of 400×240 (landscape) and the bottom one is 320×240 (landscape). When you load up a page, the page loads into the bottom screen, but you can scroll it upwards. Only half the page is touch-capable (the bottom screen). The browser is a custom webkit build, made by Netfront. It scores 125 on html5test.com. It’s cheaper than most of the other devices in my library, and it plays Zelda? Come on, how can you not love this? The big disappointment is that you can’t embed 3d images in a web page. The top screen has to switch into a separate 3d-mode to show 3d images and video.

And here’s what’s on my shopping list for the next round of upgrades:

  • An Android 2.3 device with a larger screen. Android 2.3 currently holds the largest installed base, and a lone 320×240 device just isn’t sufficiently representative 13 March 2012: target acquired. Motorola Defy+
  • The new iPad with retina display. These are going to sell by the ton, and people will be using them to browse the web all the time. Apart from wanting one for myself, I can easily see the new iPad on its own accounting for more than 10% of all mobile browsing by the end of the year. 23 March 2012: target acquired. This thing is awesome.
  • A BlackBerry 7. A touchscreen-only or keyboard-only device would be cheaper; a touch+keyboard device would cover both categories, but it much more expensive. Also, not a huge market share. Not sure about this.
  • An Android 4. There aren’t enough Android 4 devices on the market yet to give it a significant amount of market share, and therefore to worry about it as a target for testing with. I’m trusting that it’s going to be mostly like Android 3.x, but faster. I might check out the Samsung Galaxy Tab 2 7″ when it appears. Otherwise, I’ll just wait for cheaper devices.

Further reading

Website traffic patterns in the presence of native apps

A serious question for anyone running a website that has a matching native app to go with it: looking at the platform on which the app is available, is the share of website traffic from this platform going up or down (or staying static)?

My suspicion is that the share of mobile web traffic for most platforms is still going up, even in cases where a native app alternative is available.

Please comment, or contact me if you have any data to share!

A rich client tipping point

Francis Hwang talks about reaching a tipping point in web application development:

If you are writing a new web application, you should make it a rich-client application from the start. Your servers should not generate any HTML. You should do all that work in the browser with a Javascript framework such as Backbone.js or Ember.js, and the server should only talk to the browser via a REST API.

I’m very close to agreeing with this, but I have my own set of caveats.

First of all: mobile. If you’re using an iPhone 4(S), you might not realize that a lot of web browsers on mobile devices are abominably slow. In terms of getting the first page of your app/site up and running on a mobile browser, an HTML page rendered on the server is going to beat a client-side JS application hands down in at least 90% of cases.

After that first page has rendered, the comparison is different. A server-rendered site/app with full-page reloads is (probably) going to have to do more round-tripping, re-parsing and rendering, whereas a client-side app that has bootstrapped itself might only need to load up small chunks of data and refresh parts of the page. But remember that mobile devices are often tight on working memory, and even switching between tabs (let alone switching between apps) can be enough to kick your app out of memory, so that it has to bootstrap again when you switch back.

With IE6 and 7 effectively dead, the desktop doesn’t really have this problem any more. Desktop browsers are now sufficiently fast and capable that the bootstrapping cost is tiny, and from an architectural point of view separating the front-end from the back-end API is the service-oriented way of doing things, which is to say the right way.

(Then we still have to make our client-side apps internally resilient and service-oriented, so that one poorly performing component on the page doesn’t crash the whole app. But. Baby steps.)

It irks me that mobile web development, which in many ways was running ahead of classic desktop web development (advanced CSS3 capabilities, lack of IE6, et al.) is now going to fall behind in this architectural shift. Instead of incapable legacy browsers (IE6,7), we’re stuck with at least a couple of generations of poorly performing devices. The platform that is most suited to “app-like” web content is the one least capable of running the damn things.

Having said that, it’s important to know your audience. In Western Europe, at least, turnover of mobile devices is high, and the shift away from Blackberries and Nokias towards iPhones and Androids is massive. As usual, “it depends.”

Secondly, there’s the small matter of linkability and history management. If there is any part of your application that you want people to jump to directly, either as a bookmark for their own benefit, or as a link to hand out to others, it has to be have a URL. Using hash fragments for navigation may be a well-established pattern, but it’s still a hack. So long as you’re using hash fragments, that URL can only be run on the client. pushState() and replaceState() can fix this, but we’re still a little while away from these methods being universally available (IE10).

  • And then, if I’ve been clicking around in the application, what happens when I press the back button? Does it take me to a previous state within the application, or does it take me out of the application altogether? I don’t think that the field of front-end development has answered this question with a consistent set of patterns to meet (and reset) user expectations yet. Far too often I still hear, “er…don’t use the back button because that’ll break everything”.

    The back button doesn’t reign as supreme as it used to, though; multi-tab browsers have seen to that. Running an app in a dedicated browser tab, and closing it when you’re finished is a common option now. Adding a web app to your phone’s home screen so that it can run without browser chrome is less common, but on the rise. Still, the back button is likely to still be in play in the vast majority of cases. If you’re going to build an app, make sure that you have a plan to deal with it.

    Of course, none of this applies to document-oriented web content. But the distinction between apps and documents is an entirely different discussion.