Pixels Per Inch Awareness and CSS Px

Introduction

Once you realise that despite the absolute nature of many units in CSS they are still just relative, you begin to question your footing in web design, but delve deeper, and you realise it's become an answer to a problem no one had, and a problem to an answer we already had.

Absolute length units are fixed in relation to each other. They are mainly useful when the output environment is known. The absolute units consist of the physical units (in, cm, mm, pt, pc) and the px unit:

For a CSS device, these dimensions are either anchored (i) by relating the physical units to their physical measurements, or (ii) by relating the pixel unit to the reference pixel. For print media and similar high-resolution devices, the anchor unit should be one of the standard physical units (inches, centimeters, etc). For lower-resolution devices, and devices with unusual viewing distances, it is recommended instead that the anchor unit be the pixel unit. For such devices it is recommended that the pixel unit refer to the whole number of device pixels that best approximates the reference pixel.

Note that if the anchor unit is the pixel unit, the physical units might not match their physical measurements. Alternatively if the anchor unit is a physical unit, the pixel unit might not map to a whole number of device pixels.

Note that this definition of the pixel unit and the physical units differs from previous versions of CSS. In particular, in previous versions of CSS the pixel unit and the physical units were not related by a fixed ratio: the physical units were always tied to their physical measurements while the pixel unit would vary to most closely match the reference pixel. (This change was made because too much existing content relies on the assumption of 96dpi, and breaking that assumption breaks the content.)

The reference pixel is 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. For reading at arm's length, 1px thus corresponds to about 0.26 mm (1/96 inch).

The image below illustrates the effect of viewing distance on the size of a reference pixel: a reading distance of 71 cm (28 inches) results in a reference pixel of 0.26 mm, while a reading distance of 3.5 m (12 feet) results in a reference pixel of 1.3 mm.

This second image illustrates the effect of a device's resolution on the pixel unit: an area of 1px by 1px is covered by a single dot in a low-resolution device (e.g. a typical computer display), while the same area is covered by 16 dots in a higher resolution device (such as a printer).

A px is not equal to a physical pixel in all cases: this may have long been the case on the desktop during the time of no PPI awareness and ~96 PPI displays, so you can be forgiven for thinking otherwise, but it is not. They are defined as absolute in CSS 2.1, but described in a relative manner, because a device may choose to render a px any size it wants in relation to a pixel to achieve the correct PPI and viewing distance for the device. The problem is, the specification mixed this in as part of a legacy feature to support all the designs made for devices that were not PPI aware.

As specified, adjusting one of the absolute units scales them all. This forces px to be scaled away from a pixel, so that designs that assumed 96 PPI will not appear too small. Essentially, CSS2.1 further defined a px to act in a relative manner to achieve this, but now it is required to retain the relationship to the other absolute units and caused them to behave the same way. This simply undermines what a many designers who execpted a px to always be a physical pixel expected and breaks some websites, so it becomes a hiderance to PPI awareness being introduced into CSS itself. With how the px was defined in CSS 1 lead to designers believing they could no longer rely on the other absolute units, and instead were encouraged to use px instead when designing for unknown device properties, but CSS 2.1 changed that by maintaining the relationship, so it was not the case.

While it is clear from the CSS 2.1 spec that px is considered an absolute unit and as such was also treated to the They are mainly useful when the output environment is known recommendation, outside of the spec the w3c and others did not maintain px as part of this recommendation, and instead continued with the CSS 1 ideal and were told px should be used when the output enviroment is unknown too. Such an recommendation is poor and the argument could be made that you need to know you can fit things on the output, but you do not know the screen dimensions in px when using px anymore than you do for cm; if it doesn't fit, it will just have to overflow, but at least with a absolute unit based on a physical measurement, you can know your expected end result across all devices no matter the intention or treatment of a px. If that wasn't true, it would be recommened (Like CSS2.1 itself did.) no one ever used any value but a percentage value of the viewport for everything including base font-size (Which is not possible.), and run the risk of making things too small for people in some cases.

Since inception, there's always been methods of obtaining information about the device and manipulating CSS accordingly anyway, and now we have CSS 3 Media Queries that enable us to do simple best fit checks for such things without relying on those methods being present.

Looking at PPI itself, all physical measurements have a fixed relationship to each other, and a variable relationship to a pixel, and this is usually correctly specified with the pixels per inch, pixel pitch, pixel size, or pixel density. Dots per inch is not the correct unit for this purpose (Dots describe s printed ink unit that aim to produce a single colour through base units of colour, so in this case, it would be closer to sub pixels in function.), but sadly is highly misued as such by a great many (None more so than by Microsoft Windows.).

Due to historical reasons, things that are not PPI aware simply fallback on one of the two standard PPI values, 72 or 96. Today 96 PPI is the most common fallback — and was at the time CSS2.1 was written too — , and is fairly close to that of many desktop display devices. This therefore made sense as the chosen fallback for CSS too, and is used to convert between px and absolute units.

This doesn't seem too bad at first, a device should get control of final output scale to account for user preferences and view distance, but in CSS2.1 two methods are defined for this scaling process:

  1. In digital space, scale a px to be the appropriate size of a pixel at the chosen view distance. To achieve this you need to know the view distance and the size of the pixel. The latter comes from the PPI, while the former is an unknown varirable that can change on various circumstances, so this is best left to a user preference. However, those that expected a px to be a pixel will loose fidelity of their design, as pixels are for fidelity, not something that needs to be upscaled for readability.
  2. In physical space, scale a different absolute unit to match the size of the corresponding physical unit using the device PPI. This works fine, and all you need to know is the PPI instead. However it suffers from the exact same problem, because it actually procudes the exact same result.

Handling bitmaps becomes an issue using these methods. Those that were — incorrectly — defined with px dimensions would be scaled in both cases. Those that were not given a defined width — including images — would sitll be using a physical pixel, so would appear larger or smaller depending on the level of adjustment made, and would have no relationship at all to the CSS, clearly undesirable. This lead to easy solution of simply using zoom options to increase everything instead, or using an PPI defined value in an image for scaling. This puts an extra burden upon designers and handling of inconsistent behaviours.

Creating a zoom fuction to handle PPI also creates confusion and difficulty for users making adjustments for accessibility and view distance, and those trying to setup their PPI correctly.

To make matters worse, the two leading operating systems — Microsoft Windows and Apple Mac OS — have long confused the matter through mislabled and hidden settings, and again do not provide a full PPI solution. If they perhaps resolved this, the user-agents would be able to more easily follow suit. Microsoft's own Internet Explorer simply takes its own OS's lead and is not fully PPI aware despite claims to otherwise, and confuses the matter by treating users to zoom and font size settings instead.

One user-agent rendering engine in particular decided to also handle this problem in a way that fits the CSS 1 definition and allows adjusting the PPI relationship between px and the other absolute units to any level required. The only problem with this solution, is that the PPI value reported to media queries remains 96, so it looses the benefits of being better for handling images too. All other browsers instead provide only the css2.1 style method, with a selection of only a few common fixed PPI values and then zooms to match them. This doesn't create a desirable results for users or designers.

There is also two different zoom options that should be employed. PPI and optimal view distance for immediate view surfaces such as screen and paper can use the methods designed in CSS 2.1 or by changing the DPI relationship, however an accesibility zoom for the visually imparied should be changing scale wouthout changing fidelity, and as such PPI values themselves should not be adjusted.

Sadly, the future is not hopeful for better PPI support and the future of an absolute px is bleak. Popular mobile — and some desktop — user-agents have gone the root of using a px to pixel ratio or mapping setting through an abstract layer seperate from the view distance zoom. While this may keep the zooming seperate, it does make it harder to design content to display correctly on such devices without prior knowledge of their settings. This consideration is leading one engine in particular down a bad path: Webkit. Sadly they resolve this by asking a designer to specify a target PPI or Px to Pixel ratio setting, and adjusting how the user-agent functions, which it then uses to display as intended. So instead of simply supporting PPI correctly and scaling the absolute values, designers are now asked to provide various intentions through detection to scale too. This is simply backwards and roundabout logic of creating problems to solutions and places further burden on designers again.

To resolve the mess we are placed in, CSS3 needs to break the fixed relationship between px and the other absolute units, with px always being a physical pixel as far as CSS is concerned. The default relationship between them should remain 96 PPI for PPI unaware user-agents and specify they use the second scaling methods for all cases, but if a user-agent is PPI aware, then this relationship should be adjusted to match and thus no scaling method is needed for PPI itself. This way, designers can use absolute units other than px with knowledge that it will appear correctly no matter what. The fist scaling method is then used for view distance, while general magnification type scaler for pixels is used for accessability reasons, but these should never cross over into adjusting for PPI itself. That puts a nail in the conffin of confusing and muddied waters of the various zoom and accesibility features for text and browsers, and encourages them to switch to the same method as Gecko once used.

It would cause issues for websites with px sizes that expected a pixel to always be 0.01041666666666666666666666666667in (1px @ 96 PPI) — which is what they really should have specified --, and rightly so this should be a legacy case that is corrected for because we're not out to break the web, but by forcing the legacy behavour on the future, it breaks future prospects of it too. This is something that can be handled through a number of different methods eg. a CSS 3 property such as unit-scale: ppi|legacy with a default of legacy when not present, specifying that CSS3 must have a version indentifier, discouraging the use of px for the future and allowing px to remain as 0.01041666666666666666666666666667in and make scaling anchor from a physical pixel as a CSS pixel unit should not really be needed, or simply the existance of CSS 3 properties causing a switch in behaviour. This may seem a similar concept to IE's compatibility modes, and it is, because Microfsoft had good reason to need such a thing to support those that relied on improper behaviours and this is no differnet.

The result would be user-agents specifying base font-size in other units — likely pt — and designers need only use em and % from there for layout, with using in/cm only when called for.

The correct way to deal with bitmaps in such a future, should be for the designer to query the device PPI through media queries to provide some stepped PPI image replacements for closer resolution matches — this can not currently be done in CSS due to no ability to modify a src attribute or replace an <img> with a background-image, and this is really something that needs to be changed. These should then be given explicit dimensions if the intent is for them to be scaled further to match, as this is the natural behaviour of CSS, and those dimensions already provide what a specified PPI value would. Ultimately the future will be to move everything over to SVG or similar, but that future isn't quite here yet when devices still capture in bitmaps and not metrics and colour data.

This would all happen within the CSS layout process, as it's a process that the designer needs to be aware of. The PPI reported by the device is therefore true, accurate and practical to ignore except for bitmaps. Any zooming done after that to change readability should be transparent to CSS, all CSS would know is that the viewport and device dimensions appear to change as the concept of a physical pixel is scaled, but not tell it the PPI has changed so it can be used to added fidelity when it isn't wanted. If the device or user-agent is not PPI aware, then it will have to fallback on zooming as covered by the legacy support, again transparent to CSS.

Sadly, the CSS3 Media Queries spec is very unclear. While all other units are well defined CSS units and thus should scale when PPI adjustments and viewing distance zooms are made (Which several user-agents don't do, which is against the spec.), the dpi and dpcm units are not actually defined in CSS and it does not describe what should happen when a user-agent changes the PPI or zooms. As knowing the base PPI of the device in terms of physical units is useless in CSS just like it would be for dimensions, it can only be assumed that these are intended to truely mean pixels per a CSS in, cm or mm unit, which would be required to know for handling different PPI images correctly. Perhaps because this is unclear a proprietry property for querying has been added by some venderos, called device-pixel-ratio, which reports physical pixels per CSS px unit. Webkit user-agents report this instead of resolution, and still they do not scale this when zooming. Gecko user-agents do treat this value correctly and scale it when zooming, so it actually supports both, when they essentially provide the same information. However, if the alternative method of changing the PPI by changing the relationship between px and other absolute units is developed further, then this would not change, and instead it would only change when zooming for readability, so it ultimately becomes a value to indicate zoom level, which may be useful.

I hope we can reach this future of well implemented PPI solutions and encourage everyone back to absolute values before it's too late. Why do we need another solution that creates more problems, when we already had a solution that worked fine if we had stuck with it?

It's time we moved on from the fixed 96 PPI age, it serves no purpose to maintain that relationship for the future, and a more rudimentry scaling process only works as a fallback.

Note: To free up confusion and differences between metric and imperial units, it would probably be wiser to stop using PPI, the misused unit DPI, and other similar units. Instead, we should simply allow users to specify the pixel size with a value of either mm or in — this is commonly known as the pixel pitch — which is usually documented and listed for devices more readily.

The test

The following is a two fold test for common PPI values in px and their relationship to some other absolute values, and for you to check if your user-agent is using the correct PPI value by measuring (Use a rule or tape measure.) the other absolute values. All non-px absolute values should be equal; if they are not, then your browser is rounding incorrectly and that id not an issue covered here. If there is any blurring of edges, then you are likely using a zooming method to simulate PPI support or your user-agent does not map values to physical pixels — another issue not covered here.

The bar you see at the top of the page is to check correct support for CSS 3 media queries and the units used for them. The values returned should also be PPI aware if the user-agent is and thus as the viewport reaches the right edge — or edge - scroll bar width according to spec — of the bar, it should change from green to red.

[Relative] Pixels @ 72 PPI

This should be 400px wide and match the absolute values if you are using a display with 72 PPI. If it does not, then your browser is not truly PPI aware.

[Relative] Pixels @ 94 PPI

This should be 522.22222222222222222222222222222px wide and match the absolute values if you are using a display with 94 PPI. If it does not, then your browser is not truly PPI aware.

[Relative] Pixels @ 96 PPI

This should be 533.33333333333333333333333333333px wide and match the absolute values if you are using a display with 96 PPI. If it does not, or it does but you knew you are using a different PPI, then your browser is not truly PPI aware.

[Relative] Pixels @ 120 PPI

This should be 666.66666666666666666666666666667px wide and match the absolute values if you are using a display with 120 PPI. If it does not, then your browser is not truly PPI aware.

[Relative] EMs

This should be 40em (12pt * 40) wide — unless your browser has overridden the specified font-size.

[Absolute] Points

This should be 400pt wide.

[Absolute] Inches

This should be 5.5555555555555555555555555555556in wide.

[Absolute] Centimeters

This should be 14.111111111111111111111111111111cm wide.

Currently observed results should be as follows:

IE8+
PPI aware UI.
Uses method 1 as a zoom to both simulate PPI and perform view distance adjustments using a a custom zoom setting. The result is not transparent to CSS and results in unintended behaviours and dimensions. (It will use the PPI set in Windows XP+, but these are a fixed selection that are mislabled to match up with the zoom levels for this exact purpose. You can use a custom value for OS PPI in the registry, but IE8+ will only use the nearest fixed selection of zoom values to simulate it. Thankfully, IE8+ does allow you to set a custom zoom value regardless, so you can still achieve almost exact results of PPI simulation results.)
Correctly adjusts reported resolution when zooming.
Does not round units correctly — floors at arbitrary points instead.
Does not round units to pixel boundries so — over — blurs absolute units other than px.
Chrome/Safari/Android/iOS
PPI aware UI.
Uses method 1 as a zoom to both simulate PPI and perform view distance adjustments using a fixed selection zoom setting.
Webkit itself is capable of using a custom pixel to px ratio setting and this is used by mobile user-agents that have much higher PPI values, but this feature is not exposed to Safari or Chrome on the desktop.
Does not report resolution. (It reports px to pixel ratio instead, which is not part of CSS 3, and it fails to adjust it when zooming.)
Rounds units to pixel boundries so they are always sharp.
Firefox 3
PPI aware UI.
Uses a true PPI adjustment setting as layout.css.dpi to use OS set PPI value or make custom adjustments.
Uses method 1 to simulate PPI adjustments using the layout.css.devPixelsperPx setting to make custom adjustments.
Uses method 1 as a zoom to perform view distance adjustments using a fixed selection zoom setting.
Uses method 1 only on font-size to both simulate PPI and perform view distance adjustments using a fixed selection zoom setting. This produces undesriable results when using a combination of em and other units.
Correctly adjusts reported resolution when zooming or scaling.
Rounds units to pixel boundries so they are always sharp.
Firefox 4+
PPI aware UI.
Ignores the layout.css.dpi setting to force 96 PPI for CSS units.
Uses method 1 to simulate PPI adjustments using the layout.css.devPixelsperPx setting to make custom adjustments.
Uses method 1 as a zoom to perform view distance adjustments using a fixed selection zoom setting.
Uses method 1 on only font-size to both simulate PPI and perform view distance adjustments using a fixed selection zoom setting. This produces undesriable results when using a combination of em and other units.
Rounds units to pixel boundries so they are always sharp.
Opera 9+
PPI aware UI.
Uses method 1 as a zoom to both simulate PPI and perform view distance adjustments using a fixed selection zoom setting.
Does not adjusts reported resolution when zooming.
Does not round units correctly.
Rounds units to pixel boundries so they are always sharp.