Preferences

hasLayout.net

3px Gap Bug

[ Home | CSS Bugs | 3px Gap Bug ]

Table of Contents

Diagnosis

Affected browsers:
All versions of Internet Explorer below version 7.
Visual appearance:
Elements next to a floated one either have a three pixel gap or drop below or keep shifting when several elements are floated.
Triggers:
Presense of floats. Effect progresses if haslayout, margin or width is present.
back to top

Overview

Here is a rather interesting bug. In IE elements with haslayout set to a true value act differently around floats. They don't want to go under the floats, they don't even want to touch floats, in fact, giving "layout" to an element is IE's way to contain floats. However, this bug shows itself in three different flavors. Let's take a look at the demos.

back to top

Demo

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
HTML Code:
<div id="container">
	<div id="bugger">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit.
	</div>
	<div id="victim">*cry*</div>
</div>

<div id="container2">
	<div id="bugger2">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit. 
	</div>
	<div id="victim2">*cry*</div>
</div>

<div id="container3">
	<div id="bugger3">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit. 
	</div>
	<div id="victim3">*cry*</div>
</div>
<div id="container4">
	<div id="bugger4">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit.
	</div>
	<div id="victim4">*cry*</div>
</div>
CSS Code:
#container,
#container2,
#container3,
#container4
{
	width: 500px;
	overflow: hidden; /* just containing floats */
}
	#bugger,
	#bugger2,
	#bugger3
	{
		float: left;
		width: 300px;
		background: #65A5E1;
	}
	#bugger3
	{
		background: none;
		border-right: 1px solid #000;
	}
	#victim
	{
		width: 200px;
		margin-left: 300px;
	}
	#victim2
	{
		height: 1.5em; /* just to give "layout" */
		margin-left: 300px;
	}
	#bugger4
	{
		float: right;
		width: 300px;
	}
	#victim4
	{
		width: 200px;
		margin-right: 300px;
	}

Let's break each of these demos one by one. Let's start with the first one. We have three elements. Fixed width #container, inside of which are one floated element (#bugger) and another element (#victim) with left margin set to the width of #bugger. Even though you may not see this in professional code, since arguably there is little use for width in our second child element, #victim, it is this bit that makes the bug obvious. Without #victim { width: 200px; }, but haslayout still being true the bug will introduce itself as a simple three pixel gap between #victim and #bugger which can be seen in second demo (#container2). Finally, if element next to the floated one does not have "layout" the bug will be hardly noticable. Third demo (#container3) shows the effect. The text inside #victim3 is still offset by three pixels which indicates that the bug affects inline boxes generated by text, images and alike. This is how the bug got its another name "Text Jog Bug". The bug in the third demo (#container3) may not be that obvious. However, if instead of text we would have a 200 pixel wide image, it would go down and would look pretty much as what we see in the first demo (#container).

Take a look at the last demo (#contaier4). It is clearly seen that the bug is present even if we use float: right instead of float: left.

back to top

Solution (CCS)

IE Versions Fixed

All of the affected.

Despite the fact that the fix for this bug seems like a raw blow in the jaw, "give me this piece back", it is is quite effective.

Note that in all those demos the "gap" is exactly three pixels. That is what we are going to use to fix it with the solutions varying slightly depending on how the bug manifests itself.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
*cry*
HTML Code:
<div id="container">
	<div id="bugger">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit.
	</div>
	<div id="victim">*cry*</div>
</div>

<div id="container2">
	<div id="bugger2">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit. 
	</div>
	<div id="victim2">*cry*</div>
</div>

<div id="container3">
	<div id="bugger3">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit. 
	</div>
	<div id="victim3">*cry*</div>
</div>
<div id="container4">
	<div id="bugger4">
		Lorem ipsum dolor sit amet,
		consectetuer adipiscing elit.
	</div>
	<div id="victim4">*cry*</div>
</div>
CSS Code:
#container,
#container2,
#container3,
#container4
{
	width: 500px;
	overflow: hidden; /* just containing floats */
}
	#bugger,
	#bugger2,
	#bugger3
	{
		float: left;
		width: 300px;
		background: #65A5E1;
	}
	#bugger3
	{
		background: none;
		border-right: 1px solid #000;
	}
	#victim
	{
		width: 200px;
		margin-left: 300px;
	}
	#victim2
	{
		height: 1.5em; /* just to give "layout" */
		margin-left: 300px;
	}
	#bugger4
	{
		float: right;
		width: 300px;
	}
	#victim4
	{
		width: 200px;
		margin-right: 300px;
	}
Conditional Comments:
<!--[if lt IE 7]>
	<style type="text/css">
		#bugger,
		#bugger2,
		#bugger3 { margin-right: -3px; }
		
		#bugger4 { margin-left: -3px; }
		
		#victim,
		#victim2 { margin-left: 0; }
		
		#victim4 { margin-right: 0; }
	</style>
<![endif]-->

All the code is the same as in our original demo with the exception of condcoms. The conditional match in condcom matches any IE version below 7 which is exactly the versions which 3px Gap Bug affects.

The solution involves applying a negative margin of three pixels to a floated element (#bugger element in our demos) on the side where the bug happens. Thus for the first three demos we have used margin-left. Since our last demo has value right for the float property on #bugger4 we have used the opposite, margin-right instead.

Note that it is not a magic number three. We have used value of -3px for margins in our demos only because their original value is zero. The value which should be passed to IE versions below 7 should be three pixels less than the original. Thus, if we would have used #bugger { margin-right: 30px } in our first demo, we would have used #bugger { margin-right: 27px } in the condcoms.

Now the second part of the fix. We need to zero out all the margins on #victim, #victim2 and #victim4. Why? Because of the way IE treats elements with "layout" around floats, thus in IE, due to "layout", the margins on #victim, #victim2 and #victim4 would start from the edge of the #bugger instead of going under it as it happens in sane browsers.

The margin on #victim3 is not set to zero because it does not have "layout" thus it does go under the float.

back to top
back to top

Comments

  • Zoffix

    Sun Oct 21 18:49:19 2007

    The bug is fixed by floating the element as well... will add the CS solution when I get time ;) Thanks to Facedown for pointing this out

Feel free to post your comment. Only Comment field is required. Your e-mail will not be shown; specify it if you wish to be contacted.

Your comment
back to top

Advocacy

Browsers

Use what is right for you: "Browse Happy - Online. Worry Free. Switch today!"

XHTML

Don't use it unless you understand it. Please take some time to read these articles:

CSS and Internet Explorer

Use Conditional comments

back to top