How to Disable Margin-Collapsing

How to disable margin-collapsing?

There are two main types of margin collapse:

  • Collapsing margins between adjacent elements
  • Collapsing margins between parent and child elements

Using a padding or border will prevent collapse only in the latter case. Also, any value of overflow different from its default (visible) applied to the parent will prevent collapse. Thus, both overflow: auto and overflow: hidden will have the same effect. Perhaps the only difference when using hidden is the unintended consequence of hiding content if the parent has a fixed height.

Other properties that, once applied to the parent, can help fix this behaviour are:

  • float: left / right
  • position: absolute
  • display: inline-block / flex

You can test all of them here: http://jsfiddle.net/XB9wX/1/.

I should add that, as usual, Internet Explorer is the exception. More specifically, in IE 7 margins do not collapse when some kind of layout is specified for the parent element, such as width.

Sources: Sitepoint's article Collapsing Margins

how `clear` prevent margin collapsing?

This ensures that a clear prevents any following elements from overlapping the floats.

Let's start with floats and clear for now. Floats can overflow their parent:

<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
That red box overflows!
</div>

If we add a clearing div, it never will. A clear is like saying nothing else can flow above this line:

<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<div style='clear:both;'></div>
<!-- Anything down here will not overlap the floats -->
</div>

However, margin collapsing breaks things a little, because following elements can collapse 'through' something, going all the way up to the very top of the top margin. Let's have a quick excursion into certain aspects of margin collapsing.

Self collapsing hacks

In general, margin collapsing applies to any top margin which is directly touching any bottom margin.

That includes an elements own top/bottom margins too. This is called self-collapsing, and margin collapsing happens repeatedly. Here's a quick example of both of these things together:

<div style='margin-top:30px; margin-bottom:30px;'></div>
<div style='margin-top:30px; border:1px solid black;'>
The gap above me is only 30px, not 90!
</div>

That first div entirely self-collapses, resulting in a computed space of 30px, then the second div collapses into that too, keeping the space at just 30px.

Ok, so we've now got a rough idea of what self-collapsing is. Now let's start trying to abuse that with a self-collapsing clearing div:

<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<div style='clear:left;margin-top:90px;margin-bottom:90px;'></div>
I'm after the clear and look, no 90px gap!
</div>

The margin is still there though. It actually runs 90px upwards over the floats.

Next, imagine there was no text after it, and the parent had a bottom margin. By our margin collapsing rules, it should collapse upwards. Sibling elements might even collapse 'through' it, all the way up to the top. We don't want that, because it would cause some unwanted overlapping.

This part of the specification blocks this behaviour. Let's break the spec's language down to make that clearer:

If the top and bottom margins of an element with clearance are adjoining

This is describing a self-collapsing element which has cleared a float.

its margins collapse with the adjoining margins of following siblings

It's fine for other margins to collapse into it, but..

That resulting margin does not collapse with the bottom margin of the parent block.

..the very bottom margin must not collapse upwards, because that would result in our awkward overlapping case.

Here's an example of the case where the rule is applied:

<div style='border:1px solid green;'>
<!-- A parent block with a bottom margin, and no border -->
<div style='margin-bottom:50px;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<!-- A self collapsing cleared div -->
<div style='clear:left;margin-top:50px;margin-bottom:50px;'></div>
<!-- The parents bottom margin is adjacent to our collapsed margin,
but it gets blocked from collapsing upwards. We see a gap here -->
</div>
</div>

Adding some text into that clearing div makes it no longer self collapse, but its bottom margin then safely collapses with the bottom margin of the parent instead.

How do I uncollapse a margin?

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>

How to prevent margin to overflow in CSS?

Simply make the container a flex container and you will have the shrink effect that will fix the issue. Then adjust the margin of the middle one to keep the same spacing like when you had margin-collapsing (flexbox disable margin-collapsing).

#a { height: 33%}#b { height: 17%}#c { height: 50%}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css"><div class="container border border-warning d-flex flex-column" style="height: 400px">  <div id="a" class="row bg-primary m-2">A</div>  <div id="b" class="row bg-secondary mx-2">B</div><!-- margin only on the left and right -->  <div id="c" class="row bg-info m-2">C</div></div>

How to avoid margin collapse of two elements inside their respective parents?

The grid layout mode doesn't collapse margins:

body {
display: grid;
}

.block {
margin: 8px 0;
height: 20px;
width: 40px;
border: 1px solid red;
}
<div>
<div class="block"></div>
</div>
<div>
<div class="block"></div>
</div>

Why overflow:hidden can’t prevent margin collapsing in sibling divs as display:inline-block?

Margins between sibling block formatting contexts established by block boxes don't intrude into either context, so margin collapsing is allowed to happen as normal. The kind of margin collapsing that's prevented by creating a new BFC is that between the parent that establishes the BFC, and any in-flow block-level child boxes.

The reason margins between inline-blocks don't collapse is not because they establish block formatting contexts, but because margins between siblings only collapse when they are block-level boxes, never when they are inline-level boxes (inline, inline-block, inline-table or whatever).

Margin collapse issue between div

Ideally border should prevent margin collapse. What is the mistake here? I have not applied any positioning or float.

Borders do not block margin collapse between siblings — they only block margin collapse between a parent and a child, or wherever the borders would otherwise intersect the margins.

From the spec:

Two margins are adjoining if and only if:

  • ...
  • no line boxes, no clearance, no padding and no border separate them
  • ...

Since the borders aren't actually separating or intersecting the margins between your two div elements, the margins are considered adjoining, and therefore margin collapse occurs between them as usual. The borders on your div elements would however prevent margins of your divs collapsing with those of their p children.

How to adjust my div's position without collapsing margins?

You can use a tiny padding-top on the container (1px), then the margin of the child will remain within the container: