Sub-Pixel Problems in CSS

Something that jumped at me, recently, was a rendering dilemma that browsers have to encounter, and gracefully handle, on a day-by-day basis with little, to no, standardization.

Take the following page for example. You have 4 floated divs, each with a width of 25%, contained within a parent div of width 50px. Here’s the question: How wide are each of the divs?

The problem lies in the fact that each div should be, approximately, 12.5px wide and since technology isn’t at a level where we can start rendering at the sub-pixel level we tend to have to round off the number. The problem then becomes: Which way do you round the number? Up, down, or a mixture of the two? I think the results will surprise you, as they did me.

Opera 9

Safari 3

IE 6

IE 7

Firefox 3

Firefox 2

We have three completely different camps here:

Round the numbers down – Both Opera and Safari round down the widths of all the divs to 12px. This leaves a 2px gap (note the green) to the right of all the divs. If you’ve ever wondered why your nicely-aligned navigation doesn’t fill up the full contents of a container in these browsers, now you know why. On the plus side, at least you know what the width of these containers will all be the same, no matter what.

Round the numbers up – Both Internet Explorer 6 and 7 round the widths of all the divs up to 13px. Doing this causes the floated divs to immediately wrap, breaking layouts. This is obviously wrong as it causes many safely-numbered layouts to break for no obvious reason.

Round some numbers up and some down – Both Firefox 2 and 3 mix the rounding of the div widths to 12px and 13px. The mix of rounding is done as to provide an even result at the end (making it flush with the far edge). The obvious side effect is that the divs no longer have a consistent width to them (even though an equal width was specified by the CSS). Additionally, the reported (via a JavaScript computed style call, like offsetWidth) width of the element remains at its reported 12.5px not providing the user with any indication of which way the rounding is occurring. And to add another confusing wrench in the works: The order of which divs have a width of 13px or 12px has been flip-flopped in Firefox 3. This was done to improve efficiency and speed and seemingly little, to no, effect on general web site rendering.

I was talking this over with some Mozilla developers and David Baron explained the situation quite well:

We’re trying to meet a bunch of constraints that can’t all be satisfied at the same time (the proof is left as an exercise to the reader, though I may have actually written it out once in a Bugzilla comment):

1. 4 adjacent objects of width/height 25% (for example) starting at one edge of a container should end exactly at the other edge; there should never be an extra pixel in the container and they should never be wrapped due to being a pixel to wide

2. objects that are logically adjacent should always touch visually; there should never be a pixel gap or a pixel of overlap due to rounding error

3. objects given the same width should occupy the same number of pixels

4. object boundaries should always (visually) be aliased to a specific pixel boundary in the display (they should never be blurred)

The one [Mozilla] sacrifices is typically (3), except for borders where we sacrifice (1) by rounding the widths to pixel boundaries much earlier.

The especially strange part, in all of this, is that there’s really no right, or wrong, here. How this behavior is supposed to play out by the rendering engine isn’t dictated by the CSS specification, having it be left up to the implementation to render as it sees fit. Obviously the four guidelines outlined by David, above, could serve browsers well but they are forced to sacrifice at least one of them in order to meet most of them.

The whole situation is quite fuzzy and frustrating – I’m not sure what the best action is, moving forward, but at the very least it’s in the open now where we can think about it some more.

Thanks for this article, it’s good to see someone took his time and tested it. Once a designer really made me mad, when he said my layout is one pixel off when he switches to full screen – of course it was caused by rounding :)

When setting background:url() center something or when using margin:x auto and when one of the two elements you are trying to align has an odd width and the other an even width, each browser uses it’s own rounding method to calculate the center.

I saw this when I created a design that needed to be accurate by the pixel and on every browser, and sometimes (in Opera for example) in the same browser but in different widths of the viewport, I had an offset of one pixel.

The whole rounding issuse troubles me a little, for the simple reason that there is already a long standing accepted mathematical method of rounding numbers. If it is 5 or above round it up or if it is below 5 round it down.

I would content that if anything was added to CSS3, it should be that this simple rounding method should be used along with a specification. Yes that may leave us with yet more legacy problems but we will need to correct inconsistencies in the specification at some point .

“The whole rounding issuse troubles me a little, for the simple reason that there is already a long standing accepted mathematical method of rounding numbers…”

Michael – don’t you see that if you adopt this rounding scheme you get the Internet Explorer result, which is atrocious and should never be allowed to happen. Floats being made collectively larger than their container, against the expressed wish of the web-developer, is catastrophically worse than shaving a little off by rounding down.

Adopting standard rounding would be stupid, it doesn’t sounds like you’ve understood the issues here.

I ran into this problem with scriptaculous while working on the blinds/accordions on http://www.nasa.gov. The difference in subpixel calculations between IE and the other browsers caused some animations to do a “pixel-wiggle” in a really obvious way. Expanding elements with other elements underneath them were particularly affected — it was really obvious they were wiggling up and down by one pixel (which makes me surprised this issue hasn’t been covered before). Some debugging in Firebug revealed similar results to yours: Browsers were applying a mix of ceiling, floor, round, semi-round.. etc.

My quick+dirty hack was to clone scriptaculous’ Effect.Morph into a new class called RoundedMorph which would use Math.round to force all pixel sizes to the pixel grid instead of the subpixel grid. It doesn’t seem expensive or problematic at all, but it is a worrisome ambiguity in CSS.

> I’d like to see a browser sacrificing David Baron’s number 4
> above…

The effect of doing that in this case would be that the boundary pixels of the “test” floats would be partially transparent. In other words, instead of the red lines you see now in Firefox you would instead see partially transparent red at all the boundaries, with green shining through.

would have a 1px thick brownish stripe down the middle. That’s pretty undesirable as well. If there were no background on the parent, the white default background would be shining through, giving a lighter green stripe. Similar issues would arise with adjacent borders if the widths are not integer pixels, etc, etc.

Dropping constraint 3 basically makes simple cases work sanely. “Broken” complex cases can be produced no matter what approach one takes.

The solution is really to stop trying to outsmart the browser and just use subpixel positioning in your code and not worry about it. If something is claiming to be 12.5px wide, and you want to create something else that’s the same width, just set it to be 12.5px wide.

This does cause problems with APIs like offset*, which only return integer pixels. As roc says, you want to either use computed style or the bounding rect APIs instead.

But it should not be solved by any standards. The situation is a mistake of the designer. Basic math teaches you that you can not divide 50 into four equal integers. A designer should be aware of this and should avoid this situation. Just make sure that the content of a container can be divided evenly.

If there are 4 boxes in a container, make sure that the width of the container is a multiple of 4.

I’m going with TAKA on this one!
Sounds like this is a flaw in your transition from the initial design to layout. I don’t think we can say any designer would hand me a design and there be a box that is 50px wide and needs to be divided into 4 sections at 25%! What exactly would possess a developer to write a div width of 50px and then set 4 inner divs – or whatever – at 25% widths? I would hope he knows that 50 divided by four doesn’t equal even pixels and find the proper widths. Obviously in a pixel divided environment this would be a problem. I think this is a great example of why not to use percentages when they don’t divide evenly! (in case anyone didn’t already know that) Thanks for the good read!

Peter_L wrote:
“Michael – don’t you see that if you adopt this rounding scheme you get the Internet Explorer result, which is atrocious and should never be allowed to happen. Floats being made collectively larger than their container, against the expressed wish of the web-developer, is catastrophically worse than shaving a little off by rounding down.
Adopting standard rounding would be stupid, it doesn’t sounds like you’ve understood the issues here.”

It wouldn’t be the first time that I have misunderstood an issue but my comments aren’t usual classed as stupid.

However my misunderstanding of the issue leads me to believe that any designer should have a correct set of specifications to work with and in my very humble opinion the rounding of element width/height should not be left to best interpretation of browser designers. This can only (and has) lead to a variation in implementation… bad. If we cannot agree to use the accepted mathematical method of rounding, perhaps you could enlighten as to how the rounding should implemented?

Personally I agree with others who have suggested that, if the layout is correctly implemented then the rounding problem will be a non issue (Taka and Michael Plant)… but then I my not be understanding the issue correctly.

Jake Archibald wrote:
From a design point of view, I’d expect 4 elements of 25% width to equal the width of the parent,

Michael_H writes:
And from a design point of view I would agree but at this stage of development, computer do not process floating numbers accurately. Instead the computer returns an estimation of a computed floating point number. In other words rounding takes place and when your four elements do not divide equally into the size of the parent element some kind of rounding must take place. We just don’t seem to agree on how the rounding should be achieved.

Jake Archibald wrote:
but I do see the problem of them differing by a pixel.
Rounding up is the wrong answer, the other two are acceptable compromises.

Michael_H writes:
I am not advocating *rounding up* as the answer. What I did say was the I felt that adopting the mathematical method of rounding up or down, depending on the values, would be a way forward.

But at the end of the day I really do not care which way is best as long as it is implemented as standard across browsers. As you say the other solutions are both compromises and no matter which method is implemented as a standard as a compromise it will always have flaws.

Jake Archibald wrote:
Michael_H, Taka, Michael Plant:
Although John’s example uses a fixed-width parent element, this problem is most noticeable when using a fluid-width parent element.

Until computer technology advances we are stuck with this bug (for the want of a better term). Even if ’rounding down’ is adopted, as a lesser of two evils, your layout will still not be pixel perfect. I would therefore content that the designer should design the layout to avoid the possibility of uneven number division where possible.

With that said, I would like to thank John for researching and creating this article, which should prove valuable to many designers (both new and old) when designing their sites.

I’m still missing something in these last few comments. Given that in a browser which drops constraint 3 everything works as long as _no_code_ rounds (that is, as long as the web page uses fractional pixels as needed), what exactly is the problem? The only issue I see is that the offset* APIs round, and the solution there is to not use them….

Boris wrote:
I’m still missing something in these last few comments. Given that in a browser which drops constraint 3 everything works as long as _no_code_ rounds (that is, as long as the web page uses fractional pixels as needed), what exactly is the problem?

Michael_H writes:
There is no problem Boris. I was merely offering my views, which can be ignored at will…. I will not be offended

I agree that dropping constraint 3 is one way of solving the issue but it still does not specify how the browser designers should implement the rounding. I have been suitable convinced that simply adopting the mathematical method will not serve as a solution to maintaining the integrity of a layout. I still however do not believe that it should be left open to interpretation, as this will only lead to inconsistencies in display across browsers.And yes as web designers/developer we have little alternative only to accept what is on offer but someone mentioned commenting on the CSS3 draft, which I feel should give guidance on this issue.

Boris wrote:
The only issue I see is that the offset* APIs round, and the solution there is to not use them….

Michael_H writes:
Agreed

OK, I think I have said enough for now, so I’ll step aside and make room for others.

Excellent article. I’ve been aware of this for a while (particularly in IE) but never really looked into it. I certainly didn’t realise Opera and Safari always round down, that seems terribly wrong, and it’s certainly something that needs standardizing.

I think Firefox’s behaviour is the most logical, as long as the different widths are consistently different ie. if you have four columns at 25% and under that two columns at 50%, the middle lines should line up perfectly.

@ Thomas: not really, becsue then you have to position the element absolutely which is not at all flexible and is not really reliable method for layouts… perhaps application layouts, or specific needs, etc… (like this simple box illustration).. but for a layout in general, absolute positioning is never a “simple way” to fix anything… ;) hehehe

@Matt: Well there are probably situations where absolute positioning will get in the way, but I am using “absolute” for 99% of all the work I do, and I rarely experience any problems. I find it much more flexible than using floats.

@thomas: how does one resolve things like an element to clear the abolutely positioned column? say you want a footer to drop below two absolute containers…. absolute elements do not “push” other content because they do not “take up space” in the physics of the DOM… without javascript, i’m hard pressed to come to a solution to this problem…. would be very interested to hear your insight on techniques…

I’ve hit this problem quite a few times myself, drawing the same conclusions you did.

My view on things is that there should be a way to compute all values relative to the main container. Meaning that whatever the rounding method is, all elements together fill up the entire width of the container.

It’s something I’ve been thinking about myself (and should write about), but the way widths are currently handled is a bit of a drag. If you have a div of 50px wide and you have a left column of 15px there is no real need to state the width of the right col. There needs to be a way to just “fill it up”. Same goes for the procentual widths in your example.

It doesn’t really matter how the first three cols are rounded, but the fourth col should just fill up the remaining space. You will get some minor layout differences, but none as worse as those above.

In a related matter, I once wrote an article how to try and fill up that remaining space using css techniques that are currently available. Ain’t easy to do cross-browser :)

Would it not be more practical to adjust the width of the outer container so that it become divisible in whole numbers rather than fractions, then divide the innards equally in whole numbers? Would this not eliminate the need to deal with rounding up or down issues?
It seems to have worked for me in previous situations of this type.

This problem is especially apparent in liquid layouts. Right now I’m fighting with Firefox because I have a 25% column and in that column I have a 100% table. The computed-style width for the column is 310.733px. The computed-style width for the table is 311px. Guess what that means?! Horizontal scrollbar! Yea!

That’s not the worst part though. The scrollbar thumb is the entire width of the scrollbar. So it doesn’t even allow a 1px scroll. It just sits there, mocking me…

And this problem happens every fourth pixel when changing width. So these scrollbars appear and disappear when resizing the window nearly causing epileptic seizures…

The benefits of this method is that there will be no more than a 1px difference in the width of the widest and skinniest divs no matter how many divs are in the equation. Also, any 100% width items inside the divs will have a concrete width off which to calculate their width.

IEs fix for the problem breaks layouts terribly, so its out.
Safari & opera, and firefox’s methods all seem ok to me – assuming Firefox is in examples in which there are an odd number of elements, firefox is rounding down more elements than it is up, for otherwise it would turn out like IE.
I’d prefer sacrificing #4: object boundaries should always (visually) be aliased to a specific pixel boundary in the display (they should never be blurred) but anything other than 1 seems OK to me.

There is a bigger problem with opera (9.26 on mac). It rounds down percentage-widths, before calculating the actual width of the element. The roundings become very large and apparent on large sizes. Take this example:

The inner block above should (obviously) be 999px wide. Safari and Firefox displays this correctly. Opera however round the percentage down to 99% before it calculates the width, so inner block is rendered as being 990px. This is a big problem when dealing with elements of dynamic width in a dynamic layout…

had a look at what you say for ie6, but that is one of my browsers, and well if i set a parent div to 50px; and add 4 divs of 25% inside that – all floated left; well the fit perfectly, that is until i screw with the margins,padding,borders.