Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS: Em rounding error

Tags:

css

rounding

em

Recently, I've rewritten the CSS file for a site I'm making and tried to make most elements and fonts dynamic in size using em instead of px. The sizes work.. kind of, but there's at least one issue.

When using the em unit for the margins of a box (margin: 0.25em), in Firefox I get 4px at the top/left and 3px at the right/bottom - based on 14px font-size (which is actually the box's font-size 0.875em of the browser's 16px).

Now, I'm new to em and it's quite possible that I've misunderstood several things but using my understanding, I'm thinking that 0.25em of 14px is 3.5px. If this is the case, and rounding is the cause of 4 or 3 pixels in the margins, is this really how it's supposed to work? A certain calculation with a rounded result should round the exact same way every time, no? Also, in Internet Explorer, it's the exact opposite: top/left are 3px and right/bottom are 4px.I tried changing the value to 0.286em (x 14px -> 4.004px) to avoid ending up at exactly half a pixel and this turns out as 4/4/4/4 in Firefox but 4/3/4/3 in IE.

Other than these pixel errors, changing the browser font-size actually scales everything very nicely.

Am I crazy, have I misunderstood something, are both browsers broken or.. what? (Used IE8 and FF3 and 19.)

like image 228
LGT Avatar asked Apr 06 '13 01:04

LGT


2 Answers

Inconsistent rounding = smooth scaling

A browser may round a certain value up sometimes and round the same value down at other times, so that on the whole rounding operations even out.

The best example of this is when a page is scaled. Pages are usually scaled on mobile devices, but can also be scaled on a desktop browser if the user manually zooms the page. When a page is scaled, px values that used to be integers are now floating-point values. Likewise, em or % values that used to translate to an integer value in px, now translate as floating-point values.

For the browser to be able to plot the size or position of elements in terms of screen pixels, it must round each value to an integer. The rounding only works well if it evens out on the whole.

Example

Let's say you have 3 floated divs that are 100px each, for a combined width of 300px. The page is scaled on a mobile device to be 2/3 the usual size. The combined width of the scaled divs should be 200px.

If the (roughly) 66.7px of each scaled div is rounded up, each one will be 67px, which adds up to 201px (1 too many). If each div is rounded down, each will be 66px, which adds up to 198px (2 too few). The only way to have the sizes add up to 200px is if the rounding is inconsistent (rounding two of them up, rounding the other one down).

When the scaling is applied to absolutely-positioned elements with both position and size values, or to elements with a background image taken from a sprite file, any unevenness in the rounding of the scaled elements can be very noticeable.

Browser support

The last time I checked, Firefox is the only browser that does an effective job of scaling pages, of evening out the rounded values the right way. Other browsers may do some amount of this (and hopefully are getting better at it), but have not done as well in the past.

This approach -- that works so well for page scaling -- is probably the same type of behavior that you're encountering, though it may not be obvious at first glance why it's happening.

like image 168
Matt Coughlin Avatar answered Oct 14 '22 10:10

Matt Coughlin


They're not really broken in that sense. Different browsers just implement pixel rounding in different ways.

You're better off using either coarser values that don't end up in decimal values, or exact pixel values instead of ems if you need such fine-grained measurements. Remember that ems are relative quantities; they're designed for scaling, rather than for situations where precision is required.

like image 38
BoltClock Avatar answered Oct 14 '22 11:10

BoltClock