A pixel is not a pixel is not a pixel

Yesterday John Gruber wrote about the upped pixel density in the upcoming iPhone (960x640 instead of 480x320), and why Apple did this. He also wondered what the consequences for web developers would be.

Now I happen to be deeply engaged in cross-browser research of widths and heights on mobile phones, and can state with reasonable certainty that in 99% of the cases these changes will not impact web developers at all.

The remaining 1% could be much more tricky, but I expect Apple to cater to this problem by inserting an intermediate layer of pixels. (Later John pointed out that such a layer already exists on Android.)

One caveat before we start: because they’re unimportant to web developers I have mostly ignored the formal screen sizes, and I’m not really into disucssing the ins and outs of displays, pixel densities, and other complicated concepts. So I might use the wrong terminology here, for which I apologise in advance.

What web developers need

I do know what web developers are interested in, however. They need CSS pixels. That is, the “pixels” that are used in CSS declarations such as width: 300px or font-size: 14px .

These pixels have nothing to do with the actual pixel density of the device, or even with the rumoured upcoming intermediate layer. They’re essentially an abstract construct created specifically for us web developers.

It’s easiest to explain when we consider zooming. If the user zooms in, an element with width: 300px takes up more and more of the screen, and thus becomes wider and wider when measured in device (physical) pixels. In CSS pixels, however, the width remains 300px, and the zooming effect is created by expanding CSS pixels as much as is needed.

When the zooming factor is exactly 100%, one CSS pixel equals one device pixel (though the upcoming intermediate layer will take the place of device pixels here.) The image below depicts that. Not much to see here, since one CSS pixel exactly overlaps one device pixel.

(I should probably warn you that “zoom 100%” has little meaning in web development. Zooming level is unimportant to us; what we need to know is how many CSS pixels currently fit on the screen.)

The following two images illustrate what happens when the user zooms. The first shows device pixels (the dark blue background) and CSS pixels (the semi-transparent foreground) when the user has zoomed out. The CSS pixels have become smaller; one device pixel overlaps several CSS pixels. The second image shows device and CSS pixels when the user has zoomed in. One CSS pixel now overlaps several device pixels.

Thus our element with width: 300px is always exactly 300 CSS pixels wide, and how many device pixels that equals is up to the current zooming factor.

(You can calculate that factor by dividing screen.width by window.innerWidth — on the iPhone. Browser incompatibilities are rife here; expect a full report in the not-too-distant future. Besides, as a web developer you’re not interested in the zooming factor, but in how many pixels (device or CSS) fit on the device screen.)

This system will not change. If it did, all iPhone-optimised sites would become severely un-optimised in a hurry, and that’s something Apple wants to prevent at all cost.

Thus, a fully zoomed-out website would still display at 980 CSS pixels, and how many device pixels that equals is unimportant to us.

The tricky bits

However, there are two tricky bits: the device-width media query and the <meta name="viewport" width="device-width"> tag. Both work with device pixels, and not with CSS pixels, because they report on the context of the web page, and not on its inner CSS workings.

The media query

The device-width media query measures the width of the device in device pixels. The width media query measures the total width of the page in CSS pixels, which, for reasons I’ll explain later, is at least 980px on the iPhone.

The device-width media query works as follows:

div.sidebar { width: 300px; } @media all and (max-device-width: 320px) { // styles assigned when device width is smaller than 320px; div.sidebar { width: 100px; } }

Now the sidebar is 300 CSS pixels wide, except when the device width is 320 device pixels or less, in which case it becomes 100 CSS pixels wide. (You stil follow? This is complicated.)

By the way, in theory you could use a media query that queries the device screen in centimeters or inches ( @media all and (max-device-width: 9cm) ). Unfortunately it seems badly to outright unsupported, even by the iPhone. The problem here is that physical units such as inches are usually translated to (CSS) pixels; thus width: 1in equals 96 pixels on all browsers I tested so far (and that’s quite a few). So these media queries are unreliable.

The <meta> tag

In general <meta name="viewport" content="width=device-width"> is even more useful. This tag, originally Apple-proprietary but meanwhile supported by many more mobile browsers, actually makes the layout viewport fit the device exactly.

Now what is the layout viewport? It’s the area (in CSS pixels) that the browser uses to calculate the dimensions of elements with percentual width, such as div.sidebar {width: 20%} . It’s usually quite a bit larger than the device screen: 980px on the iPhone, 850px on Opera, 800 on Android, etc.

If you add <meta name="viewport" width="device-width"> , the width of this layout viewport is constrained to the device width in device pixels; 320 of them in the iPhone’s case.

That matters if your pages are narrow enough to fit in the screen. Take this page without any CSS width statement and without the <meta> tag. It stretches over the full available width of the layout viewport.

This is probably not what you want. You want to fit the text nicely on the screen. That’s the task of <meta name="viewport" width="device-width"> . When you add it, the layout viewport is contracted (to 320px in the case of the iPhone), and the text fits.

Apple’s changes

Now what impact will Apple’s resolution changes have on the device-width media query and the <meta> tag? Of course I cannot be certain, but I expect that nothing will change for web developers.

The <meta> tag

The <meta> tag is easiest to explain. Apple has deliberately invented it precisely in order to allow people to fit their content on an iPhone screen, and has pushed it with developers. That means that it can’t afford to change the device width as read out by the <meta> tag now.

In fact, the Nexus One has already blazed a trail for Apple to follow. Its official screen width (in portrait mode) is 480px, but when you apply the <meta> tag it acts as if the screen width is 320px, 2/3rds of the official width.

If I understand correctly, this is what John Gruber is saying when talking about the Nexus’s display and its missing one sub-pixel and thus 1/3rd less pixels. That fits the Nexus interpretation of the <meta> tag exactly.

So basically Google has already inserted a layer of what are apparently called dips ; device-independent pixels. This layer comes between the official, reported screen size and the CSS pixels web developers work with.

I expect the new iPhone to copy the Nexus trick and report the screen size as 320px (half of the formal resolution, in other words) when queried by the <meta> tag. It’s half and not two-thirds because the pixel density of the new iPhone is higher than the Nexus (or something).

The media query

That leaves the device-width media query as the sole problem area. On the Nexus it uses 480px as the screen width, despite the fact that here, too, 320px may be more appropriate. We’ll have to see what Apple does here.

The more fundamental question is whether the dips are also going to be used for media queries. On the whole I’d say we want that; formal device size is unimportant to web developers: we want to know how much content we can get on the screen, and it seems dips are most suited for that.

Unfortunately the Nexus does not do that right now; as far as media queries are concerned the device-width is still 480px, and not 320px. But maybe Apple can solve this problem for web developers.

So the situation is quite clear for normal websites and for those that use the <meta> tag; less clear when it comes to media queries.

Stay tuned.

Comments are closed.