Home

CSS Sub-pixel Background Misalignments

Nov 18, 2008

Update: and now, IE8 adds even more odd behavior to the mix!

A while ago, John Resig pointed out some issues with sub-pixel positioning in CSS. The problem he used is one of percentage-sized columns inside a container, where the resulting column widths don't round evenly to whole pixels or don't sum to the correct total. His conclusion is that browsers each have their own way of dealing with the problem.

I've recently been bumping into a related issue however, that shows the situation is even worse: rounding is inconsistent even inside a single browser.

Take the following scenario: a fixed width element that is horizontally centered in a viewport using margin-left: auto; margin-right: auto;. The viewport has a horizontally centered background image, having background-position: 50% 0. This is an extremely common page structure.

You'd logically expect the background image and the element to line up, and move as one when the viewport is resized. However, this is not the case. Depending on the viewport width, the background can be offset one pixel to the left or right. This obviously wreaks havoc on many designs. I decided to investigate this more closely and the results are not pretty.

My test case consists of the basic structure described above, repeated in a bunch of mini-viewports. Each background image contains a black box of a certain size, and is overlaid with a grey element that covers this box exactly. If the two pieces align, there should be no black peeking through on the sides, and each box should be fully gray.

For full coverage, I vary the following parameters:

  • The width of the viewport
  • The odd/even size of the box/element
  • Background image is bigger/smaller than the viewport
  • Background image is padded evenly/unevenly around the box (1px difference). (*)

I tested this in IE6, IE7, Safari 3.1.2, Firefox 3.0.4 and Opera 9.6.2.

The result is quite baffling: not a single browser out there rounds background image positions the same as element positions, resulting in misalignments. The tell-tale black lines show up in every browser:

IE6 and IE7:

Safari 3.1 and Opera 9.6:

Firefox 3.0:

What's worse is there isn't a single case (across viewport sizes) that is handled consistently between all the browsers. So this CSS technique should in fact be considered broken.

Of course this brings up the question: is it really a browser bug or just an implementation quirk? I would argue that at least in the case where the image's width parity matches the element's, you'd expect perfectly matching rounding (i.e. for the first four rows of test cases). The other test cases are more ambiguous, and all you could hope for is consistent behaviour in each browser individually.

I wonder why this hasn't been brought up more though. A quick sampling of designers around me shows that they have all encountered this bug, but don't really know a fix and just tweak the design or layout structure to mask the effect.

If you really do need to align a background image properly, there is an ugly work-around: place your background image on an additional fixed-width element layered behind the center column. Center the background's element using margins rather than the background image itself, and clip it off at the sides using overflow: hidden on an additional wrapper. This causes the background's position to be rounded the same way as the column on top.

(*) Note that there is a choice whether to pad more on the left or on the right. I chose the left. This means that the last 4 rows of test cases are inherently ambiguous: a browser that misaligns all of these in the same fashion is in fact being consistent, just in the opposite direction.

There IS a sort-of work around to this..

Nov 19, 2008 Corey Dutson

I found it a while back when I was running into the same thing.

I found a solution somewhere ( can't for the life of me remember) and it works out to be something like this:

body {
  background: url('whatever') top center repeat-y;
  /* Set up your repeating background shim. For this I'm assuming it's a border that wraps around an 800 pixel wide container*/

  padding:0px!important; /*this padding hack fixes things */
  padding:0px 0px 0px 1px;
  text-align:center;
}

#container {
  width: 800px;
  margin: 0px auto;
  text-align: left;
}

This will align a container in the center of the page (800 px wide), as well as adjust the background to always be in the correct center.

The issue itself is called the "Jogging Background bug" and from what I have found, this generally fixes it. I haven't used it in a while, but my old example still works, and it's in Firefox 3 so...

In any case it's a silly bug that shouldn't even exist. I mean really, how hard can it be for everyone to round to the same point?

@Corey: Are you sure?

Nov 19, 2008 Steven

Your fix should only affect IE6, due to the use of the !important trick, and even then, it only adds a one pixel offset (thus simply inverting the shift/no-shift bit). I just tried it myself and I still get the same pattern of pixel jogs that my test case revealed.

I tried both Standards and Quirks mode too. Same deal.

I found the following page that mentions your fix, and in fact it shimmers in Firefox 3 for me (look at the red header):
http://www.pmob.co.uk/temp/onepxjog.htm

In Safari 3, it doesn't shimmer except when the viewport is smaller than the image size.

This is all on OS X. Are you getting different results on the test cases?

This is really curious. Good

Nov 21, 2008 Carlos Hermoso

This is really curious. Good post

Hmm,

Nov 26, 2008 Alexa Booth

Interesting case, Steven. Hm, I'll have to think on if I have done anything to fix this in the past. I've noticed this before, but just passed it off as being a quirk, and not really attempted to fix.

This worked for me

Nov 26, 2008 Joe

Great topic, it has bugged me for a long time. I started thinking about it and thought if it is a rounding problem, then maybe the browsers would have trouble rounding odd width background images and fix itself. Well, for Firefox it worked, and IE 7 it worked too. I guess it has to do with the fact you cannot split a pixel.

Anyway, I hope it works for everybody else.

@Joe: covered in the test case

Nov 26, 2008 Steven

The test cases I used cover all combinations of odd/even width, and show no consistent behaviour for any of them. What numbers did you plug-in exactly for the different variables (i.e. column width, image width, viewport width)? Did you use browser specific tweaks? Also, did you test Safari/Opera?

I looked at your site and its structure differs from this problem: your vertically repeating background image is set on a fixed-width element, not on the viewport, and consequently your page cannot shrink beyond the width of the background.

The point of this blog post is that when the background container's width needs to be variable, rounding behaviour becomes inconsistent and impossible to harmonize.

I know...

Nov 26, 2008 Joe

Sorry, I didn't give you the home page of the site I actually am using it on as it is still on our testing server. It is a repeat-y graphic in the body. Background image width is 961px (meant to be 960px). The page overlaying it is 920px in width as the background image is the shadow and columns of the page. It definitely works for me, but I have not tested it on Opera or Safari. I had a similar problem with my previous site, which is now http://www.2005.spicy.com.au. I am not sure now if it is the "oddness" about the image, or just the fact that if it occurs it is fixed by adding a pixel.

All I know it is working here for me and I am stoked that I can continue to finish the design. I did notice you did the testing with different widths, so I am clueless as much as you seem to be.

Decimals?

Nov 27, 2008 Joe

Just as a thought, has anyone tried using eg: 49.99% for the left positioning? Maybe that way it always keeps it to the left. I will test and keep you informed when I get a spare moment.

Padding or Margin!?

Dec 02, 2008 John

Joe inspired me to try tweaking the number being used to center the "wrapper". Instead of 49.99% I simply put a pixel of padding on EITHER the left or right side of the wrapper, and it worked (a) for my site (and b) in IE7.

I'd be curious to know if this works for other designs/browsers -- I wanted to post this idea before I completely forgot rather than wait until I can validate it.

Curiously, it doesn't matter whether I use a pixel of padding or margin or which side I add it to -- worked in all instances. If somebody would like to explain that to me...

...works to a point

Dec 03, 2008 John again

Hmmm. Today I look at the same code and I see the pixel offset when I use margin or padding on the right (or none at all). It's pretty obvious so I don't understand why I didn't see it yesterday.

Adding a pixel to left margin or padding seems to work until the browser window becomes narrower than the background image. Then it appears to offset 50% of the time, implying that the rounding hack stops working when the background image's LEFT position would be a negative number.

Intersting

Feb 05, 2009 Fotografi

Really intereting, thanks for this tip.

Just wanted to say thanks

Feb 18, 2009 Steve

Just wanted to say thanks for documenting this; have spent a total of six hours rehashing my site thinking it was just my maths not adding up! Added 1px to the right of my wrapper and happy days are here again

same issue

Feb 27, 2009 D-3ent

My site is having the same issue with the red vertical bar displayed in the site. Looks great in FF obviously, but 1 shim off in IE7. I had adjusted the math before to even numbers, and that had fixed it. Still showed up off in IE6 though.

http://www.d-3entertainment.com

This was a rush site, so I didn't get too involved with a CSS structure. There's obviously some involved, but will I have to go full on if I want everything to line up properly... at least in FF and IE?

Fixed my alignment issues.

Feb 27, 2009 David Haynes

I fixed my alignment issues in Firefox with this JS snipet;

<script type="text/javascript">
window.onload = resizeIfOdd;
window.onresize = forceBrowserEven;

function resizeIfOdd(){
if(navigator.userAgent.indexOf('Firefox/3') != -1 ||
navigator.userAgent.indexOf('WebKit') != -1)
if(document.documentElement.clientWidth % 2 == 1)
window.resizeBy(-1,0);
};

function forceBrowserEven(){
window.setTimeout('resizeIfOdd()',5);
};   
</script>

Also, the the IE hack that I think might have been mentioned is this;

body { margin-left: 1px }

Obviously you'll need separate stylesheets for the IE hack to work.

One word of caution though, my site in which I've fixed the issue is www.gamerzunite.com and I recently tried to use Adbrite to buy some advertising for it but one of their rules says that you can't use JS code to re adjust the browser! So my ad was denied. :(

Regards,

David
www.davidahaynes.com

RE: Fixed my alignment issues.

Feb 28, 2009 D-3ent

I'm not having any issues in FF, just IE. I've tried this hack, but it didn't change anything.

body { margin-left: 1px }

IE8

Mar 03, 2009 David Levin

Has anyone tested this issue in the up and coming IE8 browser? Two things that really piss me off about css is the lack of consistent height 100% support and accurate centered rounding.

IE is the Devil...

Mar 05, 2009 Cameron Schuyler

I'm in the same boat with you guys. IE isn't working for me, but Firefox is fine with a 1px padding-right style added to my repeating background. I tried using conditional code for IE with no luck:

< !--[if IE]>

#mainbg {
margin-left: 1px;
}

< ![endif]-- >

I need your help, fellow gurus of the web.

I've never found a fix for this

Mar 09, 2009 Jared Lyon

I researched this a bit about a year ago, and found absolutely no fix. I also found a lot of people saying they have a fix, and every person that said they had a fix, when I looked into it, their fix didn't work, or it was not the exact same issue.

Good luck! :)

Easy fix?

Mar 11, 2009 Aaron Cicali

Of course there is the obvious solution. Make the background image accompany either flavor of rounding. For instance - your background image has a right side and left side and in between would be where your page falls. Just take the right side of the image and shift it left 1 pixel, or a few pixels just to be safe.

There will probably never be a solution to the actual problem, it'd be like asking the browser developers to all switch to a singular rendering engine. We can always dream though, right?

Safari 4

Apr 04, 2009 Rob

Congratulations to us all - it looks like Safari 4 only exacerbates the issue. I've been trying for two days to get it to play while also fixing Firefox 3.0.8 and IE. No luck.

Oh, thank the CSS Gods

Apr 13, 2009 Thomas

Almost ready to hurl my computer at the screen ... until I added one pixel to my outer wrapper and VIOLA. Right as rain, no jagged misalignment. Thanks, guys!

Thanks

May 24, 2009 Riad Marrakech

I've encountered the same issue, and no solution found !
I just fall on your blog and I want to thank all those who participate in finding the solution

A quick comment

Jun 11, 2009 Brendon

Hi i know this is an old post but seems fairly active still. I am in no way a css expert but i have brought the problem down to the fact that you cant centralize an image either with an odd amount of pixels or a browser window size with an odd amount of pixels.

What i mean is say you had an 800px width image. you can center it up on a 1000px browser window size without a drama. But if you resize your browser by 1px to lets say 1001px your content may move while your background image stays put as you obviously cant halve pixels.

I tried grabbing the right side of my Firefox browsers width and slowly scaling it outwards pixel by pixel and watch the problem appear then disappear each time.

Has anyone really cracked the problem yet?

FIXED in Safari 4, Chromium, IE6, IE7

Jun 14, 2009 Ric Lewis

Here's a fix for a problem that only appeared in the above browsers (across OSX10.5 and WinXP). It did not appear in FF3 and IE8.

My code had two DIVs taking up the full width of the window, one inside the other, each with a centred BG. The 1 pixel jog showed up on window resize.

I tried a number of fixes (and there are a lot of them out there) but the one that worked for me was this:

HTML

<div class="main-content-bg-rpt">
<div class="main-content-bg-static">
</div>
</div>

CSS Fix applied via some browser detection voodoo
div.main-content-bg-static{
margin-left: 1px
}

That's right - 1 pixel margin left on the inner DIV.

Feel free to experiment on your own scenarios - try a negative margin, try the outer DIV, try both at once. Now I have centred backgrounds across FF3, Safari 4, Chrome(ium), IE6-7-8 (sorry Opera!).

big thanks

Jul 13, 2009 Thomas Css

Ric, you are God.

That fix actually worked for me. I wish I had this link in the morning :)

keep divs together to maintain alignment

Jul 17, 2009 Glenn

The only way to really keep the divs from misaligning is to tie all the divs together so that they all move together.

For example, if you have a background image set in the body and then divs which need to align to that image, you'll get a 1 pixel shift depending on the browser window width.

My solution was to create a wrapper for the background image and then contain my page elements tightly with no margins inside a 'content' div. Everything moves together. I then place any divs that require margins further inside.

It takes a little planning but you can often eliminate the 1 px shift by laying out your divs differently. The code is a bit messier but it does work.

You can't always do this but it often works. I still run into trouble where I have two background images that I need to align.

I did try the javascript above and it seems to work though I noticed that there's some latency. The divs align after a second.

I was having this same

Aug 07, 2009 Stevo

I was having this same issue, I just changed my values to even numbers, and problem solved. If you can find a way to just shift your design a little, making the values even that you intend to center seems to fix the problem for me.

IE8 fix

Sep 01, 2009 Carolina Bolanos

I had this issue as well, but I had the main div aligned (right and left) to auto so it would center the div. In an internal div I had a corner in background mode that had the 1px difference in IE. Since I couldn't do the: margin-right: 1px; I did: padding-right: 1px;

#top {
width: 950px;
height: 360px;
margin-right: auto;
margin-left: auto;
display: block;
padding-right: 1px; /* I did this instead */
}

#top #top-der {
margin-top: 51px;
float: right;
height: 309px;
width: 721px;
background-color: #E2DED5;
background-image: url(../images/box-corner.jpg);
background-repeat: no-repeat;
background-position: right top;
}

It works fine now in IE6, IE7 and IE8.

elements moving 1px when scrollbar is present

Sep 08, 2009 davy

Hi, Just found this site because I was looking for a fix to a strange 1px problem.

I noticeed I got this problem on Safari & Chrome lately.

a header was the only element that shifted 1px to the left when all other centered elements were staying put.

the solution was to add padding-left:1px to the offending wrapping element, worked for me in both scrollable pages and non scrollable pages, and still kept my background image as an even number, same as the element it was in.

I hope others may find this useful... it is a workaround that has worked for me so I thought I would share.

Hi all, nice to see the

Sep 23, 2009 Tsvetan

Hi all, nice to see the problem discussed somewhere on the web! :) It's solved in FF 3.5.x!!
Making the background-containing div with fixed width and auto margins on the side fixes the problem. The background shadow is not that wide anyway so a width of 1000px will do fine on 1024 screens too.

A Good Fix for some situations

Jan 12, 2010 Buck Manhands

Hi

I found this solution on another blog and it works well in some situations. Basically if you have the background image starting at 0 0 instead of centered then this will not shift at all. Then you put a margin 0 auto on the containing div at the size you need and the problem went away for me. Here was the original post I found:

terje (the original poster)
A very anoying bug indeed, however there is a permanent solution that works with any window size, you have to use a container element though.

If you have a centered background with a width of 960px you write something like this:

div#container { width:960px; margin:0 auto; background:url(/images/bg.gif) repeat-y 0 0; }

Proper alignment of a body image

Jan 18, 2010 Tim Wolf

I tried everything that is suggested here. I also though up some of these semi-solutions myself, but no luck.

It's not even that big of a problem aligning a background making it centered in all browser windows. My biggest problem is a background-image that I want to repeat vertically. And because height: 100%; is a big nono, I can't use any of these solution presented here.

Has anybody tried the following?

<div id="left"></div>
<div id="right"></div>
<div id="yoursite"></div>

div#left{
float: left;
width: 50%;
z-index: 1;
position: relative;
background: url(left side of bg image);
}

div#right{
background: url(rightside of bg image);
float: left;
width: 50%;
z-index: 2;
position: relative;
}

div#yoursite{
width: 990px;
z-index: 3;
margin: 0px auto;
position: relative;
}

The only time this does not work, is when people have really outdated display, with resolutions as small as 800x600. But If you have a resolution as low as 1024 your safe.

So is there a way we can influence the WebKit developers?

Feb 27, 2010 Nemanja Ćosović

Since we cant find the answer for this one using normal techniques, why don't we appeal to the idiots that created the damn thing in the beginning.

Someone send them an email or petition or whatever!

woooooooo..

Mar 18, 2010 Server

so great! Thank you !

Post new comment

Note: all posts containing spam will be removed.
The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <b> <dd> <dl> <dt> <i> <li> <ol> <u> <ul> <img> <em> <p> <br> <span> <div> <h2> <h3> <abbr> <small> <table> <tr> <td> <strong> <acronym> <th> <blockquote>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

Recent comments

Images