Why Doesn't a Child's Margin Affect a Parent's Height

Why doesn't a child's margin affect a parent's height?

What you are looking for is called collapsing margins. One reason that margins collapse so that empty elements do not add vertical margin space and also to evenly space elements without the need of resetting their margins.

From the specification:

3. Margins

Note: Adjoining margins in block layout can collapse. See CSS2§8.3.1 Collapsing Margins for details. Also, margins adjoining a fragmentation break are sometimes truncated. See CSS Fragmentation 3 §5.2 Adjoining Margins at Breaks for details.

The first link in that quote is to this:

8.3.1 Collapsing margins

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.

Adjoining vertical margins collapse, except:

  • Margins of the root element's box do not collapse.
  • If the top and bottom margins of an element with clearance are adjoining, its margins collapse with the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block.

You can add an overflow property to the parent element to fix this (either auto, hidden, or something else depending on your needs).

JSFiddle Example: http://jsfiddle.net/k1eegxt3/2/

Why don't a child's vertical margins expand their parent container?

The answer to "why" is described well and succinctly here. There are certain properties that establish a "block formatting context". Namely:

Floats, absolutely [and fixed] positioned elements, block containers (such as
inline-blocks, table-cells, and table-captions) that are not block
boxes, and block boxes with 'overflow' other than 'visible' (except
when that value has been propagated to the viewport) establish new
block formatting contexts for their contents.

It is this change of block formatting context that is the reason why such solutions as given above in the comments work for how margin (and in the case of a preceding float, padding of following inflow elements) operates.

Why does the child div's margin affect the margin of the parent?

Margin collapse. See references below for some examples on avoiding it.

https://developer.mozilla.org/en-US/docs/Web/CSS/margin_collapsing
http://reference.sitepoint.com/css/collapsingmargins

See fiddle - overflow hidden applied to .pannel
http://jsfiddle.net/pTTQQ/

.pannel {
width: 100%;
padding-bottom: 10%;
overflow: hidden;
}

.pContent {
width: 90%;
height: auto;
margin: 0 auto 0 auto;
margin-top: 3%; /* Why can't this be margin top? */
}

Margin on child element moves parent element

Found an alternative at Child elements with margins within DIVs You can also add:

.parent { overflow: auto; }

or:

.parent { overflow: hidden; }

This prevents the margins to collapse. Border and padding do the same.
Hence, you can also use the following to prevent a top-margin collapse:

.parent {
padding-top: 1px;
margin-top: -1px;
}

2021 update: if you're willing to drop IE11 support you can also use the new CSS construct display: flow-root. See MDN Web Docs for the whole details on block formatting contexts.


Update by popular request:
The whole point of collapsing margins is handling textual content. For example:

h1, h2, p, ul {
margin-top: 1em;
margin-bottom: 1em;
outline: 1px dashed blue;
}

div { outline: 1px solid red; }
<h1>Title!</h1>
<div class="text">
<h2>Title!</h2>
<p>Paragraph</p>
</div>
<div class="text">
<h2>Title!</h2>
<p>Paragraph</p>
<ul>
<li>list item</li>
</ul>
</div>

Why does margin child element affect body element?

You will achieve your goal, if you modify the body css to the following:

body {
background-color: green;
height: 100%;
width:100%;
margin:0;
position: absolute;
}

/* Another technique */
remove top-margin:50px, and wrap your toto div with another div and give it padding-top:50px; as per below:

html {

background-color: red;

height: 100%;

}

body {

background-color: green;

height: 100%;

margin:0;

}

#container { padding-top:50px; }

.toto {

background-color: blue;

width: 100px;

height: 100px;

}
<div id="container">

<div class="toto">

</div>

</div>

Cannot get child DIV % height to work because of parent margin auto

If your parent has an auto height, I'm afraid this is not possible.

The parent will always extend to contain all the children, so its height depends on the height of the children.

If your children also depend on the parent height, you have a infinite loop.

I think the only solution is to go with some Javascript, with which you can get the parent height dynamically and apply the right height to the children.

Or maybe if you don't need the auto height on this page you can override the template-contents's height directly in the source so it does not apply to other pages ?

<html>
<body>
<div class="flexer">
<div class="template-container">
<div class="template-contents">
<!-- Cannot change anything above this line -->

<style>
.template-contents {
height: 100%;
}
</style>

<div class="ztop" style="background: rgb(200,0,0,0.3);">
I am 80% of Parent Height
</div>
<div class="zbottom" style="background: rgb(0,200,0,0.3);">
I am 20% of Parent Height
</div>

<!-- Cannot change anything below this line -->
</div>
</div>
</div>
</body>
</html>

Why doesn't margin-right work if the child div bigger than it's parent?

margin-right is working, but .container2 is bigger than its parent and you don't see the effect. Remember browsers render from left to right, from top to down.

If you want to have a visible right margin, no matter the .container2 width, you need to set float: right;

.container2 { 
width: 105%;
border: 1px dotted red;
height: 200px;
margin-right: 10%;
position: relative;
float: right;
}

Why would margin not be contained by parent element?

This is how CSS works according to W3C:

In this specification, the expression collapsing margins means that adjoining margins (no non-empty content, padding, or border areas, or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin.

More specific to your case of the top div:

If the top and bottom margins of a box are adjoining, then it is possible for margins to collapse through it. In this case, the position of the element depends on its relationship with the other elements whose margins are being collapsed.

  • If the element's margins are collapsed with its parent's top margin, the top border edge of the box is defined to be the same as the parent's.
  • Otherwise, either the element's parent is not taking part in the margin collapsing, or only the parent's bottom margin is involved. 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.

The best thing I can do is point you to on "Collapsing Margins" on sitepoint (by Tommy Olsson and Paul O’Brien). They do a very detailed explanation with examples showing you exactly the behaviors you demoed in the question example code.

Why does a negative bottom margin on an element decrease the height of parent of that element?

This might be due to margin collapsing and I know about margin collapsing, at least how it affects adjacent elements, but I don't understand how it works on nested elements when negative margins are involved.

Section 8.3.1 has all the details. It also covers the behavior of adjoining margins between nested boxes, as well as negative margins.

However, what you're seeing here is not the effect of margin collapse because you have negated it with a border: 1px solid black declaration in your .parent rule. That means having a border there prevents your .parent margin from collapsing with your .child.negative margin altogether.

Rather, this is simply how negative margins work. This is covered in various sections of the visual formatting model, but it's most succinctly and directly addressed in the beginning of Section 11, which summarizes it thus:

Generally, the content of a block box is confined to the content edges of the box. In certain cases, a box may overflow, meaning its content lies partly or entirely outside of the box, e.g.:

  • ...
  • A descendant box has negative margins, causing it to be positioned partly outside the box.

So what's happening here, instead, is:

  1. The absolute value of the .child.negative element's negative margin is subtracted from the .parent element's actual height (by 1px).

  2. As a result, the .child.negative element itself overflows .parent (because its own height is not changed and the default overflow for any div is visible).

  3. Since margin collapse does not take effect here, the margin-bottom: 10px in your .parent is unaffected. Note that while any subsequent elements in normal flow will be shifted up by 1px, this is mainly due to the negative margin of your .child.negative element; in other words, a side effect of step 1.

And that's all there is to it.



Related Topics



Leave a reply



Submit