How Is the Margin-Top Percentage Calculated

How is the margin-top percentage calculated?

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;
};

margin-top: calc(%) is using percent of width rather than desired percent of height

Per the css spec, percentage values for margin, including margin-top, are based on / calculated from the width of the containing block.

If you are referring to the height of the window, you can use vh instead of percent:

margin-top: calc(100vh - $value);

Margin-top percentage not relative to parent

Vertical padding and margin are relative to the width of the parent. Top and bottom on the other hand are not.

Try to place a div inside another. Use the top property (for example: top: 25%) and make sure you specify a position (e.g. position: relative;)

I've forked and adjusted your code example to demonstrate what I mean: https://codepen.io/anon/pen/Yaqmva

top: 5%;
position: relative;

Why are margin/padding percentages in CSS always calculated against width?

Transferring my comment to an answer, because it makes logical sense. However, please note that this is unfounded conjecture. The actual reasoning of why the spec is written this way is still, technically, unknown.

Element height is defined by the height of the
children. If an element has padding-top: 10% (relative to parent
height), that is going to affect the height of the parent. Since the
height of the child is dependent on the height of the parent, and the
height of the parent is dependent on the height of the child, we'll
either have inaccurate height, or an infinite loop. Sure, this only
affects the case where offset parent === parent, but still. It's an
odd case that is difficult to resolve.

Update: The last couple sentences may not be entirely accurate. The height of the leaf element (child with no children) has an effect on the height of all elements above it, so this affects many different situations.

How to set the margin or padding as percentage of height of parent container?

The fix is that yes, vertical padding and margin are relative to width, but top and bottom aren't.

So just place a div inside another, and in the inner div, use something like top:50% (remember position matters if it still doesn't work)

Calculating margin-top value to occupy remaining height in fluid design

I think you can easily obtain what you want by using flexbox and margin-top:auto on header:

body,html { height:100%; margin:0;}
.container { height: 80%; width: 80%; display:flex; flex-direction:column; border:1px solid; box-sizing:border-box;}
.header { flex:0 0 15%; background:red; align-self: flex-start; /* To have same visual behavior as inline-block */ margin-top:auto /* this will do the trick*/}
.box { flex:0 0 40%; background:yellow;}
<div class="container">  <span class="header">Hello!</span>  <div class="box">a</div>  <div class="box">b</div></div>

margin-top in percentage not working as expected

The point is that a percentage value for top/bottom margin/padding properties is relative to the width of the box's containing block. It doesn't respect the height of the parent element.

8.3 Margin properties: 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', and 'margin'

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

As you are using absolute positioning, try using top: 99% instead in which a percentage value refers to the height of the box's containing block.

CSS - margin top of 50% is more than 50%

This is because when it comes to top/bottom margins and paddings in percentages, the values will be taken as the fractional width of the parent element, not the height. According to the W3C definition:

The [margin] 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.

This question has been addressed before in StackOverflow - see here.


Suggestion: If you would want to position an element in the center vertically, you can use the following trick instead:

  1. Position the child element absolutely
  2. Declare dimensions for the parent, such that the parent's dimensions do not rely on those of the child
  3. Position the child element 50% from the top
  4. Use a nifty trick of CSS 2D translation.

Here's the modified CSS from your fiddle that works:

.content header {
width: 100px;
height: 100px;
top: 50%;
background: red;
position: absolute;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
}

http://jsfiddle.net/teddyrised/73xkT/7/



Related Topics



Leave a reply



Submit