Collapsed Margin in CSS

Collapsed margin in CSS

The margins of #empty collapse through, resulting in a 20px collapsed-through margin. This collapsed-through margin collapses with the 10px bottom margin of the first paragraph, and the 10px top margin of the last paragraph. This results in a 20px gap between the first and last paragraphs, since the collapsed-through margin is larger than either of their margins and therefore swallows them both.

Your observation is correct: #empty, when its collapsed through, is rendered with its top margin. From the spec:

  • [...] The position of the element's top border edge is the same as it would have been if the element had a non-zero bottom border.

Note that the positions of elements that have been collapsed through have no effect on the positions of the other elements with whose margins they are being collapsed; the top border edge position is only required for laying out descendants of these elements.

The position that "would have been if the element had a non-zero bottom border" is the position of the element if the element's margins did not collapse through, since having a non-zero bottom border blocks the margins from collapsing through.

Margin collapsing in flexbox

Margin collapsing is a feature of a block formatting context.

There is no margin collapsing in a flex formatting context.

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.

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 / grid

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 to Fix Collapsing Top and Bottom Margins?

This answer is based off of the fiddle you provided.

I think your approach is incorrect in that your applying a margin to the article to space it within the parent div tag. It is better to use padding in this case, since your attempting to separate the content from its outside border. So apply:

article {
//display: block;
clear: both;
padding: 10px;
}

This will cause the article tags to increase in size, however the borders of the container div elements will now be touching. To create space between elements a margin is applied.

.rounded-box {
background-color: #959392;
border-radius: 15px;
margin: 10px 0px;
}

Working Example http://jsfiddle.net/LCTeU/4/

So just to recap, when you want to create space between two elements use margin. When you want to create space between an element and its border (or you want an element to be surrounded by whitespace) use padding.

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.

Margin collapse and clearance

Yes. Take a look at the below snippet [JSfiddle] in either Firefox or IE.¹

.case { width:200px; background-color:yellow; }
.container { background-color:lightblue; margin-bottom:70px; padding-top:0.01px; }.preface { float:left; height: 58px; width: 100px; border: 1px solid red; }.one .intro { clear: left; margin-top:60px; }.two .intro { clear: left; margin-top:59px; }
<div class="case one">  <div class="container">    <div class="preface">      lorem ipsum    </div>    <div class="intro"></div>  </div>  after</div><hr><div class="case two">  <div class="container">    <div class="preface">      lorem ipsum    </div>    <div class="intro"></div>  </div>  after</div>

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>

Why horizontal margin doesn't collapse as vertical margin?

Horizontal margins never get the chance to collapse as the rules that govern margin collapsing mean that they can never satisfy the conditions.

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

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

Adjoining boxes can only be block-level boxes:

Two margins are adjoining if and only if:

  • both belong to in-flow block-level boxes that participate in the same block formatting context

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

And margins only collapse if they are not floated or positioned absolutely:

  • Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
  • Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.
  • Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).

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

This means that block-level boxes can never be positioned on the same line horizontally (as block-level boxes will automatically start on a new line by default) and satisfy the margin collapsing conditions at the same time.

In theory, inline boxes could satisfy the conditions but as they are not block-level the rules do not apply to them at all.

In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes.

Inline formatting contexts (http://www.w3.org/TR/CSS21/visuren.html#block-formatting)

That said, the simple reason why they don't collapse is that W3C said so:

Horizontal margins never collapse.

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

What does collapsing width height and margin mean for block level elements?

A collapsed margin is the name given to the instance when margins of two different elements occupy the same space.

Consider the following example:

.box {  height: 50px;  width: 50px;}
.box1 { background: red; margin-bottom: 25px;}
.box2 { background: blue; margin-top: 50px;}
<div class="box box1"></div><div class="box box2"></div>


Related Topics



Leave a reply



Submit