Always show greater margin - html

I have given one block a bottom margin of 25px and a top margin of 10px. The total margin should then be 35px but it is showing 25px. If I give 35px margin, then it shows the total of 35px. Why is it showing greater margin always?
Here are the code lines:
<p style="margin-bottom:25px; outline:1px dashed #000000;">aaaaaaaaaaaa</P>
<p style="margin-top:10px; outline:1px dashed #000000;">bbbbbbbbbbbbbbbb</p>

It's called "collapsing margins". This is normal, and is in accordance with the W3 standards. It says:
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.
More info: http://www.w3.org/TR/CSS21/box.html#collapsing-margins
Therefore your two <p> tags:
<p style="margin-bottom:25px; outline:1px dashed #000000;">aaaaaaaaaaaa</p>
<p style="margin-top:10px; outline:1px dashed #000000;">bbbbbbbbbbbbbbbb</p>
would then collapse.
The specifications also mention cases where margins are not collapsed. For example, floated elements have non-collapsed margins:
Margins between a floated box and any other box do not collapse
And a fiddle demonstrating collapsed and non-collapsed margins:
Fiddle:http://jsfiddle.net/k8tFy/3/
(Note: you can even see the floated <p> tag is even interacting with the margin-bottom of the <h2> tag)

If short, that is how margins should work. Top and bottom margins may collapse and in that case final distance between two blocks will be equal to the width of largest margin.
For more details take a look at this part of CSS standart:
http://www.w3.org/TR/CSS2/box.html#collapsing-margins
When two or more margins collapse, the resulting margin width is the
maximum of the collapsing margins' widths.
Possible solutions:
You may simply put margin-bottom of top element to 35px, just like you described.
Another way is to make one of elements to be float:
<p style="margin-bottom:25px; outline:1px dashed #000000;clear:both;">aaaaaaaaaaaa</P>
<p style="margin-top:10px; outline:1px dashed #000000;clear:both;float:left;width:100%">bbbbbbbbbbbbbbbb</p>
Demo
Above solution based on next exception you may find on page linked above:
Margins between a floated box and any other box do not collapse (not
even between a float and its in-flow children).

Related

Why is adding or removing a border changing the way margins work?

If I have a container with an element inside that has a margin, that elements margin will not push it down within that container but instead push down the container itself. That alone, while annoying, might just be how the w3c decided it would work. But the weird thing is, if I add a border to the container that element will now be pushed down within the container and the container will then be flush against the element above (what I want). Until now most of the containers I use have had borders so that I could tell how everything was lining up, but now that I have decided to start adding background-colors and removing margins to make everything look nicer I am running in to a ton of issues with gaps between containers that have neither of the containers background colors applied to them.
In case I was not clear I created a jsfiddle to demonstrate the issue, as you can see by looking at the html / js clicking the button only toggles the existence of a border and nothing else. Yet all the margins between the containers change based on whether or not the border is there.
http://jsfiddle.net/Tysonzero/p5fgjmrn/
HTML:
<div class="first-div">
</div>
<div class="second-div">
<div class="inner-div">Test</div>
</div>
<button onclick="toggle()">Toggle Border</button>
CSS:
*
{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.first-div
{
background-color: red;
min-height: 50px;
}
.second-div
{
background-color: blue;
min-height: 50px;
}
.inner-div
{
margin: 10px;
text-align: center;
}
JS:
toggle = function() {
if (document.getElementsByClassName('second-div')[0].style.border) {
document.getElementsByClassName('second-div')[0].style.border = "";
}
else {
document.getElementsByClassName('second-div')[0].style.border = "1px solid";
}
};
I want it to always work the way it works WITH a border as IMO that makes a ton more sense, and for my project it is what I need. I really hope I don't have to do something hacky such as add a 1px transparent border to everything and compensate for it when necessary. I have tried using overflow: auto; or overflow: hidden. But neither are the same as having a border. overflow: auto; will sometimes create scrollbars if the element inside is bigger than the parent or if you are using negative margins in a certain way whereas adding a border does not, overflow: hidden; completely prevents scrolling whereas adding a border does not.
Does anyone know how I can force the browser to treat everything as though it has a border (or at least make issues like this not happen) and also can anyone explain this behavior? It seems unintentional but I could be wrong.
The specific answer to your question is collapsing margins and is part of the W3C's BOX MODEL specifications:
Vertical margins may collapse between certain boxes:
Two or more adjoining vertical margins of block boxes in the normal flow collapse. The resulting margin width is the maximum of the adjoining margin widths. In the case of negative margins, the maximum of the absolute values of the negative adjoining margins is deducted from the maximum of the positive adjoining margins. If there are no positive margins, the absolute maximum of the negative adjoining margins is deducted from zero. Note. Adjoining boxes may be generated by elements that are not related as siblings or ancestors.
Vertical margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
Vertical 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.
Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
Margins of inline-block elements do not collapse (not even with their in-flow children).
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.
An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
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.
Margins of the root element's box do not collapse.
So, when you add a border, you're doing exactly what the specification says, therefore you have no margin.
There are many ways and fixes and hacks to solve this, but to me, the most direct and easy is as simple as to apply an overflow:auto; property to the div you want to clear the margin.
Thus, in your CSS, you would only need to change it like this:
.second-div
{
background-color: blue;
min-height: 50px;
overflow:auto;
}
I forked your fiddle with even more border so you can notice the effect and see how good it works

Div positioning is changing with and without border

I'm testing some css styles on a blog-like div layout. I used div{border: 1px solid black;} to see the divs and look at its positions.
When this line is in my style, it looks right, but I don't want to have the borders (just had it for development).
As soon as I comment it out everything changes it's positions. Why is this so?
JSFiddle Link
div{border: 1px solid black;} /* Comment this to see the problem */
body{ text-align:center; }
.postTabs{
float:left;
background-color: #c8c8c8;
width: 60px;
height: 38px;
padding: 27px 5px 5px 5px;
border-radius: 50%;
}
.postContent{
padding: 15px 15px 15px 50px;
margin-left: 35px;
margin-top: 36px;
text-align: left;
background-color: #a7a7a7;
}
<div class="postContainer">
<div class="postTabs">asdf</div>
<div class="postContent">
<div class="postBody">adf</div>
</div>
</div>
This is because of collapsing margins:
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.
Also the spec states:
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context
no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for
this purpose.)
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
top margin of a box and top margin of its first in-flow child
bottom margin of box and top margin of its next in-flow following sibling
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero
or 'auto' computed 'height', and no in-flow children
In this case, the first child is floated to a side and it is removed from normal flow. Hence the first in-flow child of the .postContainer container is .postContent element which has a margin-top of 36px.
Since the container doesn't establish a block formatting context, and there's no border, padding between them, the margins would be collapsed into one.
You could prevent that by giving the container:
A padding-top of 1px - for instance - Example here.
A border-top of 1px solid transparent Example here.
An overflow of anything other than visible which creates a new block formatting context - Example Here.
For further info you could refer to the spec.
Check the fiddle here
JS Fiddle
it was happening because of float:left for .postTabs class
.postContainer{
clear: both;
float: left;
width: 100%;
}
This is because of the default box model in CSS. The element is as wide as the width, plus any padding, plus any border.
You may have expected the border to sit inside of the element, but it actually makes it wider (by 2px in your case) and taller (again by 2px).
You can adjust your width and height accordingly, or you can change the box-model being used with the CSS box-sizing: border-box;
In your case, though, you are only applying the border for development purposes, so changing your CSS to support the border will mean changing it all back again later.
Rather than do all that work, use your browser tools. The screenshot below shows the browser tools in Firefox (all browser have similar tools to this). When you highlight the element in the HTML shown in the tools, it shows the outline of the element on the actual page.
This gives you your development view whenever you need it without having to change the code.

Giving a margin to a paragraph element doesn't actually apply to parent div

Given the following markup:
<div>
<p>Test test</p>
</div>
Setting the margin: 10px to the paragraph element should apply to both top and bottom, correct?
I have a simple example, and I don't quite know why it doesn't work.
http://jsbin.com/URumOFup/2/edit?html,css,output
This works as I expect it to if I give the div the rule of overflow: hidden. Can someone explain why this happens and if using overflow: hidden is the proper way to have the margins of p apply?
The general meaning of "margin" isn't to convey "move this over by 10px" but rather, "there must be 10px of empty space beside this element."
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.
Since your outter DIV is not 'floated' .. top margin of inner element <p> will collapse to 0 for the first one, then collapse to a minimum spacing for other <p> tags.
Just 'float:left;width:100%' your div will solve your issue.
Margin-collapsing w3c reference

padding on parent turn margin of the child into height expandation

There is a block:
<div class="block">
<p>this is a paragraph this is a paragraph</p>
</div>
And its style:
.block{background:gray; width:300px}
p{margin-top:50px}
This is the result:
Well, but when I add padding-top to the .block, the result differs:
.block{background: gray; width:300px; padding-top:1px}
p{margin-top:50px;}
The result:
It looks that by adding padding to the parent, the margin of the child (p) caused expanding.
You could checkout the fiddles: http://jsfiddle.net/YFU2f/2/ and http://jsfiddle.net/YFU2f/3/
By default, adjacent margins collapse, when you introduce a padding between them they aren't anymore adjacent, so they become separate.
In your example, the top margin you defined on the p element collapses with the top margin of the body element (which is usually 8px by default), so at the end, the distance between the top of the canvas and the top of the content box of p is 50px. If you introduce the padding, it becomes 8px+1px+50px=59px. You can also notice the collapse of the margin by looking at the background of the div: when the margin collapses, it is as if the 50px margin was only declared for the body.
You can find all the details in the specifications: http://www.w3.org/TR/CSS21/box.html#collapsing-margins
you need to use display p as block
p{margin-top:50px;display:inline-block;}

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.
For example, in this markup and accompanying CSS:
Markup
<div class="parent">
<div class="child">
Child 1
</div>
</div>
<div class="parent">
<div class="child negative">
Child 1
</div>
</div>
CSS
body {
background: white;
padding: 45px;
}
.parent {
border: 1px solid black;
margin-bottom: 10px;
}
.negative {
margin-bottom: -1px;
}
Live example here.
When I inspect the height of the second .parent div, I notice it is 1 pixel less than the first one. This has happened because of the negative margin on the .negative element inside it. I had a quick look at W3C and couldn't find an explanation for this behavior.
Could someone please explain what's happening here and also provide me with a link to the W3C spec section about it?
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:
The absolute value of the .child.negative element's negative margin is subtracted from the .parent element's actual height (by 1px).
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).
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.
when you are using .negative { margin-bottom: -1px; } then it will moved at the top. see this example.
please refer the following link you understand easily.
http://coding.smashingmagazine.com/2009/07/27/the-definitive-guide-to-using-negative-margins/
body {
background: white;
padding: 45px;
}
.parent {
border: 1px solid black;
margin-bottom: 10px;
min-height: 30px;
}
.negative {
margin-bottom: 20px;
}
conclusion:
For e.g. In your case i have to added min-height:30px to parent class so that it remains fix. if moved only if you add positive margins to negative class. It just because you can see results in above figure that tells all what you need is.
see the cssdesk link click here cssdesk
Hope, it will helps you. Cheers. !!
Margins of first and last elements will apply to outer element when the outer element doesn't have border, padding and content, instead of it self.
In your case, parent node has border, so margin collapsing won't apply in this case. As you have margin-bottom = -1px for the child node inside, when calculate the outer height of the child node will be the height of its content + padding + border-width + margin. So it will be 1px less when measuring from outside. That's why the height of parent node will be 1px less than the upper example. To see it more clearly, you may apply a background to the child node, say yellow, you will find that the child node will overlap the border of the parent node.
But if you remove the border of the parent node, it will be a total different situation.
For instance to explain margin collapsing, say you have
<div style="background-color:black">
<div style="height:10px; background-color:white; margin-top: 10px"></div>
</div>
You will not see a black box of 10px height, as the outer node will be considered to have a 10px margin on top, and the inner one's margin is ignored. And for negative situation, the outer margin will decrease.
Quote from spec:
When two or more margins collapse, the resulting margin width is the maximum of the collapsing margins' widths. In the case of negative margins, the maximum of the absolute values of the negative adjoining margins is deducted from the maximum of the positive adjoining margins. If there are no positive margins, the maximum of the absolute values of the adjoining margins is deducted from zero.
For more info:
https://developer.mozilla.org/en-US/docs/CSS/margin_collapsing