How is the top margin percentage calculated?

advertisements

I know this should be straightforward, but can anybody tell me why the child boxes in the following overflow their parent's container when a margin-top: 50% is applied to the child. How is the margin-top percentage calculated?

.container {
  background: lightblue;
  padding: 10px;
  height: 200px;
}

p {
  display: block;
  border:1px solid red;
  margin-top:50%;
}
<div class="container">
<p> Some Cool content</p>

</div>

Shouldn't the child element be placed 50% from 200px (set height on parent), i.e 100px from top?


From W3C Spec:

The percentage is calculated with respect to the width of the generated box's containing block. Note that this is true for 'margin-top' and 'margin-bottom' as well. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.

There are two good reasons to base vertical margins on the width of the containing block:

Horizontal and Vertical Consistency

There is, of course, a shorthand property that lets you specify the margin for all four sides of a block:

margin: 10%;

This expands to:

margin-top: 10%;
margin-right: 10%;
margin-bottom: 10%;
margin-left: 10%;

Now, if you wrote either of the above, you’d probably expect the margins on all four sides of the block to be of equal size, wouldn’t you? But if margin-left and margin-right were based on the width of the container, and margin-top and margin-bottom were based on its height, then they’d usually be different!

Avoiding Circular Dependency

CSS lays out content in blocks stacked vertically down the page, so the width of a block is usually dictated entirely by the width of its parent. In other words, you can calculate the width of a block without worrying about what’s inside that block.

The height of a block is a different matter. Usually, the height depends on the combined height of its contents. Change the height of the content, and you change the height of the block. See the problem?

To get the height of the content, you need to know the top and bottom margins that are applied to it. And if those margins depend on the height of the parent block, you’re in trouble, because you can’t calculate one without knowing the other!

Basing vertical margins on the width of the container breaks that circular dependency, and makes it possible to lay out the page.

Example:

Here is the fiddle. And the code:

HTML

<div class="container">
  <p id="element"> Some Cool content</p>

</div>

<p>
  MORE TEXT
</p>

CSS

.container {
  background: lightblue;
  padding: 10px;
  height: 100px;
  width: 500px;
}

p {
  display: block;
  border: 1px solid red;
  margin-top: 50%;
}

JS

window.onload = function(evt) {

  var element = document.getElementById("element"),
    style = element.currentStyle || window.getComputedStyle(element);

  element.textContent = "the margin-top is : " + style.marginTop;
};