39

Collapsing margins in CSS: http://www.w3.org/TR/CSS21/box.html#collapsing-margins

I understand the purpose of the feature, but I'm trying to do layout, and I can't figure out how to turn it off.

The way usually explained in CSS tutorials is to either:

  1. Add a border
  2. Add a padding

All of these have side effects that become obvious when you're dealing with pixel-perfect layouts with background images and fixed paddings.

Is there any way to simply disable the collapsing without having to shove extra pixels into the layout? It doesn't make any sense for me to have to visually affect the document to change behavior like this.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Alex J
  • 9,905
  • 6
  • 36
  • 46

5 Answers5

28

well you need something in between to "break" the collapsing.

my first thought was to use a div with display:none set in between, but that doesn't seem to work.

so I tried:

<div style="overflow: hidden; height: 0px; width: 0px;">.</div>

which seems to do the job nicely (at least in firefox, don't have internet explorer installed here to test it...)

<html>
    <body>
        <div style="margin: 100px;">.</div>
        <div style="overflow: hidden; height: 0px; width: 0px;">.</div>
        <div style="margin: 100px;">.</div>
    </body>
</html>
Liam
  • 27,717
  • 28
  • 128
  • 190
Zenon
  • 1,436
  • 1
  • 11
  • 21
  • Works for me in Firefox, Chrome, Opera and IE6 on Linux. Good job, I was about to post that it was impossible... – DisgruntledGoat Dec 01 '09 at 21:16
  • Seems to work in IE6 as well. It's astounding that you need extra markup to acomplish this though. – Alex J Dec 01 '09 at 21:20
  • Actually, close, but not quite there. The margins are still collapsing, they're just not collapsing against eachother. Consider:
    .
    .
    .
    – Alex J Dec 01 '09 at 21:25
  • well, id you put the overflow:hidden div inside the background divs, it still works (though the markup is getting uglier and uglier this way...). like there has to be a more elegant solution to this. Though, knowing how webdesign is, there probably isnt :) – Zenon Dec 01 '09 at 21:31
  • 7
    Just as a point (bit of a necro I guess, but hey): you could use a non-breaking space (` `) rather than a period just to ensure the div will never show up. – connec May 28 '12 at 11:19
  • 3
    To add to what @connec mentioned, using ` ` instead of `.` would prevent a stray period from showing up for page descriptions in search engine results (extra spaces would most likely be stripped, but not necessarily a period). – 0b10011 Jun 08 '12 at 17:36
17

From IE8 you could do:

<div class="uncollapse-margins">
    <p>Lorem ipsum dolor sit amet.</p>
</div>
<div class="uncollapse-margins">
    <p>Lorem ipsum dolor sit amet.</p>
</div>

With CSS:

.uncollapse-margins:before,
.uncollapse-margins:after
{
    content: "\00a0"; /* No-break space character */
    display: block;
    overflow: hidden;
    height: 0;
}
andraaspar
  • 796
  • 6
  • 10
  • 2
    I'm not sure why, but this doesn't work for me. – norsewulf Dec 15 '13 at 19:25
  • @norsewulf Works for me. Here's a [fiddle](http://jsfiddle.net/y9VAu/4/). – andraaspar Jan 06 '14 at 14:54
  • 2
    @norsewulf - It only works if there is an additional block element within the container. With the specific code above, it works because of the presence of the child p elements inside the div's. If you remove the p elements or replace them with span elements this solution is inviable. [JSFiddle](https://jsfiddle.net/clarketm/y9VAu/11/) – Travis Clarke Mar 15 '15 at 03:46
12

Use Flex or Grid layout.

In flex and grid containers, there's no such thing as margin collapsing.

More details in the specs:

3. Flex Containers: the flex and inline-flex display values

A flex container establishes a new flex formatting context for its contents. This is the same as establishing a block formatting context, except that flex layout is used instead of block layout. For example, floats do not intrude into the flex container, and the flex container’s margins do not collapse with the margins of its contents.

5.1. Establishing Grid Containers: the grid and inline-grid display values

A grid container establishes a new grid formatting context for its contents. This is the same as establishing a block formatting context, except that grid layout is used instead of block layout: floats do not intrude into the grid container, and the grid container’s margins do not collapse with the margins of its contents.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
7

Eric Meyer refers to your exact point in his article Uncollapsing margins.

See the text of the article after Figure 6 for his approach. He mentions that 1px padding/border is typically the way to go, but offers a pretty simple solution for instances where there's no flexibility in adding that additional pixel.

It involves manually overriding margins on each element though, so I'm not sure if it will work for your particular case.

Mark Hurd
  • 13,010
  • 2
  • 27
  • 28
6

One neat trick to disable margin collapsing that has no visual impact, as far as I know, is setting the padding of the parent to 0.05px:

.parentClass {
    padding: 0.05px;
}

The padding is no longer 0 so collapsing won't occur anymore but at the same time the padding is small enough that visually it will round down to 0.

If some other padding is desired, then apply padding only to the "direction" in which margin collapsing is not desired, for example padding-top: 0.05px;.

Working example:

.noCollapse {
  padding: 0.05px;
}

.parent {
  background-color: red;
  width: 150px;
}

.children {
  margin-top: 50px;

  background-color: lime;      
  width: 100px;
  height: 100px;
}
<h3>Border collapsing</h3>
<div class="parent">
  <div class="children">
  </div>
</div>

<h3>No border collapsing</h3>
<div class="parent noCollapse">
  <div class="children">
  </div>
</div>

Edit: changed the value from 0.1 to 0.05. From this small test, it seems that Firefox takes the 0.1px padding into consideration. Though, 0.05px seemes to do the trick.

Nicu Surdu
  • 8,172
  • 9
  • 68
  • 108