21

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?

Scheintod
  • 7,953
  • 9
  • 42
  • 61
dkjain
  • 831
  • 1
  • 9
  • 36
  • that's because of margin `margin-top:50%;` – roottraveller Jan 10 '16 at 13:56
  • 1
    I know it's because of `margin-top:50%` but why ? Shouldn't the child element be placed 50% from 200px (set height on parent), i.e 100px from top ? – dkjain Jan 10 '16 at 13:58
  • display: inline-block; – varun aaruru Jan 10 '16 at 13:59
  • 4
    Guys, I am looking for an explanation. All those fixes could have been done by myself however I need an explanation why `margin-top:50%` is not calculated on set height of parent. – dkjain Jan 10 '16 at 14:01
  • Very strange that people with thousands of reputation points can't even understand this question. Moreover they are providing useless hacks. @roottraveller is amazing in telling the real reason which is already written by OP in his question. – Sachin Aug 05 '23 at 18:21

3 Answers3

36

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;
};
Facundo Victor
  • 3,308
  • 1
  • 25
  • 20
11

Percent-based margins are calculated using the width of the parent container, regardless of which side the margin is on.

So you're seeing a margin-top equal to 50% of the width.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 1
    Oh really, this is news to me. Any logical explanation as to why this behavior perhaps with a good example. – dkjain Jan 10 '16 at 14:06
1

if you want set percentage of height, give 'vh' a try..

{
   margin-top: 5vh; /* should be 5% of vertical container */
}

discussed here

tmx976
  • 57
  • 5