Css 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

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.

Why are margins not collapsing?

Flex items' margins won't collapse. When flex items wrap, they create their own row, and the individual margins on the flex items won't collapse between rows. Only normal, adjacent block elements stacked will margin collapse the way you're intending. This is a good reference - https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing

You can create the same layout by removing the top margin from the li's and making that a padding-top on the ul instead, then only the bottom margin will be applied between li's when the flex row wraps.

ul {  list-style-type: none;  padding-left: 0px;}
a { text-decoration: none;}
main { background-color: #F1F4F5; padding: 30px 0px;}
.main-wrapper { max-width: 800px; margin: auto;}
.tags ul { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; margin: 0; padding-top: 20px;}.tags li { margin: 0 10px 20px; display: block;}.tags a { display: block; justify-content: center; color: #3A4250; background-color: #e6e6e6; border-radius: 20px; padding: 7px 20px; transition: background-color 0.3s ease, color 0.3s ease;}.tags a:hover { color: #FFFFFF; background-color: #FC575E; transition: background-color 0.3s ease, color 0.3s ease;}
<main>  <div class="main-wrapper">    <div class="tags">      <ul>        <li>          <a href="#">ELEMENT 1</a>        </li>        <li>          <a href="#">ELEMENT 2</a>        </li>        <li>          <a href="#">ELEMENT 3</a>        </li>        <li>          <a href="#">ELEMENT 4</a>        </li>        <li>          <a href="#">ELEMENT 5</a>        </li>      </ul>    </div>  </div></main>

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.

Why does Margin Collapsing only apply to top and bottom but not left and right

Only block level elements can have their margin collapsed and if they are block level elements, they cannot have elements to their left or right.

See the following link for more information: Why horizontal margin doesn't collapse as vertical margin?

Hope this helps.

Margin Collapse for Adjacent siblings

First, the examples below only work in Gecko based browsers like Firefox on Windows or Android. Chrome/Webkit has a long history of implementing clearance incorrectly.


I think that statement is a misinterpretation of the specification. What the specification actually says is

Two margins are adjoining if and only if:


both belong to in-flow block-level boxes that participate in the same block formatting context and no line boxes, no clearance, no padding and no border separate them

So what causes clearance to have an effect here? It's not the clearance of the latter sibling, but the clearance of an intervening element.

Consider this example.

.container {  overflow:auto;  border:2px solid;}span {  float:left;  width:100px;  height:100px;  background:red;  opacity:0.2;}.container > div {  height:60px;  margin:20px 0;  background:blue;}b {  display:block;  clear:left;}
<p><strong>View this in Firefox</strong></p><div class="container">  <span></span>  <div></div>  <b></b>  <div></div></div>

CSS margins not collapsing

CSS margin collapsing only occurs vertically & under 3 circumstances:

Adjacent siblings: The margins of adjacent siblings are collapsed (except when the later sibling needs to be cleared past floats). For example:

<p>The bottom margin of this paragraph is collapsed...</p>
<p>...with the top margin of this paragraph.</p>

Parent and first/last child: If there is no border, padding, inline content, block_formatting_context created or clearance to separate the margin-top of a block from the margin-top of its first child block, or no border, padding, inline content, height, min-height, or max-height to separate the margin-bottom of a block from the margin-bottom of its last child, then those margins collapse. The collapsed margin ends up outside the parent.

Empty blocks: If there is no border, padding, inline content, height, or min-height to separate a block's margin-top from its margin-bottom, then its top and bottom margins collapse.

Take a look at Margin Collapsing here in MDN.

In your case they won't collapse, you'd better applying margin to only one side excluding last item in the row:

aside {
float: left;
background-color: yellow;
width: calc(20% - 10px);
margin-right: 5px;
padding: 10px;
box-sizing: border-box;
}

aside.last {
margin-right: 0;
}

How works margin collapsing with min-height?

That version of the Specification is probably a bit confusing. You can check the updated version (2.2) where the main rule is:

both belong to vertically-adjacent box edges, i.e. form one of the following pairs:

...

  • bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height

Then the rule you quoted will become:

The bottom margin of an in-flow block box with a 'height' of 'auto' collapses with its last in-flow block-level child's bottom margin, if:

  • the box has no bottom padding, and
  • the box has no bottom border, and
  • the child's bottom margin neither collapses with a top margin that has clearance, nor (if the box's min-height is non-zero) with the box's top margin.

The min-height is no longer there.


As a side note, the rule you quoted is an implication of the main rules listed above where there is nothing about min-height so having a margin collapsing in case of min-height different from auto won't be a surprise for me if it happens (even if it's non intuitive).

UPDATE

A related old question Margin collapsing with floated element, why there is an extra margin added?. It's now an irrelevant one since we cannot reproduce the behavior but margin-collapsing was occuring in all the cases even if the min-height was bigger than the childs height.


I guess the vertically-adjacent box edges is the key to understand what is happening. If a min-height make both elements no more adjacent then no margin collapsing will occur (which is logical), otherwise you will have margin collapsing (like in your example).

Does CSS grid suppress margin collapse inside grid items?

From the specificaton:

A grid item establishes an independent formatting context for its contents. However, grid items are grid-level boxes, not block-level boxes: they participate in their container’s grid formatting context, not in a block formatting context.

and

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.ref

So margin inside a grid item cannot collapse with the margin of the grid item that are outside

You can have margin collapsing inside the grid if all the concerned margin are inside