CSS px is an Angular Measurement

by Sean B. Palmer

The “px” unit in CSS doesn't really have anything to do with screen pixels, despite the poorly chosen name. It's actually an non-linear angular measurement. The formulæ to convert between radians and px are as follows:

radians = arctan(px/5376) * 2
px = 5376 * tan(radians/2)

Using this, you can work out the apparent angular widths of things in pixels quite easily. The moon from earth is about 24.3px wide, for example. The Eiffel Tower from a mile away is about 550.5px tall. That means that when you do “{ width: 24.3px }” in CSS 2.1, you're making something as wide as the moon looks to be.

Derivation

So where does this magic figure 5376 come from? Well according to CSS 2.1, § 4.3.2 Lengths:

“Pixel units are relative to the resolution of the viewing device, i.e., most often a computer display. If the pixel density of the output device is very different from that of a typical computer display, the user agent should rescale pixel values. It is recommended that the reference pixel be the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm's length. For a nominal arm's length of 28 inches, the visual angle is therefore about 0.0213 degrees.”

So the visual angle of a single pixel is defined by 96dpi (or ppi), and a “nominal arm's length” of 28in, which is roughly a Flemish ell. Note that in CSS 2 the value of the standard resolution was 90dpi. The model in CSS 2.1 corresponds to the following diagram, with an obviously exaggerated scale:

[Right angled triangle, opp = 1/192 in, adj = 28 in]

So using the trigonometric definition of a tangent to find the value of α we have:

tan(α) = opp./adj.
tan(α) = ((1/96) / 2) / 28
tan(α) = (1/192) / 28
tan(α) = 1/5376
α = arctan(1/5376)

The units cancel out as long as the opp. and adj. are both measured in the same way, so it doesn't matter that we're using imperial rather than metric. Since α is only half the angle that we want, we simply multiply the result by two in order to get the whole angle corresponding to 1px in radians, i.e. arctan(1/5376) * 2. To find out what the px value is in terms of radians is just a matter of rearranging that equation.

So in other words the 5376 comes from multiplying the average screen resolution as the unitless value 96, the CSS 2.1 specification's take on the Flemish ell as the unitless value 28, and the 2 required from the size of the half angle.

Quick Conversion

px
rad
°

Note what happens when you put in values of degrees approaching 180: this shows the effect of the functions being non-linear. No matter how large a value you put in for px, you'll not be able to reach 180 degrees. It'd be nice to have a to scale <canvas> implementation of this, but of course 28in at 96dpi is 2688 pixels wide. Perhaps an implementation with a scaled down horizontal axis?

Notes

Compare the Swhack logs about these formulæ.

Query: Are height and widths in HTML defined in a similar way?