hasLayout.net

Negative Margin Bug

Affected Versions

This bug affects: IE7

Symptoms

Part of the element that is outside the container disappears when negative margins are used

Date of the Tutorial

Fri Jul 17 02:53:43 2009

Description

Update: I found that solutions presented here do not fix a special setup with negative margin-right and height set to percentage values or right set to any value (even auto). I'll post an update if I ever find a solution

The bug is easy to notice. You set some margin on the element inside an element with "layout" to a negative value so it would escape a bit from its container and viola: IE cuts off the part of the element that is outside the container. Let's take look at the demo.

Demo

I am cut off
Text
More text
HTML Code:
<div id="container">
    <div id="inner">
        I am cut off<br>
        Text<br>
        More text<br>
    </div>
</div>
CSS Code:
#container {
    margin: 2em auto .5em;
    padding: 2em 0;
    width: 80%; /* width gives layout */
}
    #inner {
        margin: -4em 2em 0; /* negative margin is used */
    }

In this demo width: 80% gives the container layout which is one of the trigger requirements. When this demo is viewed in Internet Explorer the top part of #inner, the one that goes out of the #container, will be cut off.

Solutions

Below are solutions for the above bug ordered by the solution type.

Solution (Clean Solution) - with Side Effects

Date of the Solution

Fri Jul 17 03:06:49 2009

Fixed Versions

5.5 and 7

Description

The cleanest way to fix this bug is to remove layout from the container.

The methods to make an element loose layout vary. The idea is to not use any properties that give an element layout. Keep in mind that it is not always possible; for example, when properties that give layout are crucial to the page style or an element has layout by default.

Let's see how we can fix our demo using this method.

First of all, since one of the triggers is container having layout, this is exactly where we should start looking - <div id="container">. We need to loose it. How? Since the set width is in percent units (80%), let's try using margins instead. And since we already have auto value for our left and right margins, we will need to make them both equal (10% each).

Here is it, fixed demo:

I am cut off
Text
More text
HTML Code:
<div id="container">
    <div id="inner">
        I am cut off<br>
        Text<br>
        More text<br>
    </div>
</div>
CSS Code:
#container {
    padding: 2em 0;
    margin: 2em 10% .5em; /* 10% left and right margins, no width */
}
    #inner {
        margin: -4em 2em 0; /* negative margin is used */
    }

Fixed version looks the same as original demo, however the bug does not appear anymore.

Side Effects

Removing layout from the container causes peek-a-boo bug to appear in IE versions below 7. If you are supporting such versions consider using "layout solution" for this bug.

Solution (Layout Solution)

Date of the Solution

Fri Jul 17 03:11:38 2009

Fixed Versions

all of the affected

Description

This solution uses hasLayout on the element with negative margins itself as well as position: relative as an extra kick that is needed to stabilize the fix.

Here is a fixed version of our demo using this method.

I am cut off
Text
More text
HTML Code:
<div id="container">
    <div id="inner">
        I am cut off<br>
        Text<br>
        More text<br>
    </div>
</div>
CSS Code:
#container {
    margin: 2em auto .5em;
    padding: 2em 0;
    width: 80%; /* width gives layout */
}
    #inner {
        margin: -4em 2em 0; /* negative margin is used */
    }
Conditional Comments:
    <!--[if lte IE 7]>
        <style type="text/css">
            #inner {
                zoom: 1;
                position: relative;
            }
        </style>
    <![endif]-->

Everything is pretty straight forward. Giving #inner layout makes the part that is outside #container appear. And position: relative is what helps prevent the disappearing background bug.