how `clear` prevent margin collapsing? - css

margin collapse is disbled in the following case:
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.
what does it mean?can u give me some concrete examples?

This ensures that a clear prevents any following elements from overlapping the floats.
Let's start with floats and clear for now. Floats can overflow their parent:
<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
That red box overflows!
</div>
If we add a clearing div, it never will. A clear is like saying nothing else can flow above this line:
<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<div style='clear:both;'></div>
<!-- Anything down here will not overlap the floats -->
</div>
However, margin collapsing breaks things a little, because following elements can collapse 'through' something, going all the way up to the very top of the top margin. Let's have a quick excursion into certain aspects of margin collapsing.
Self collapsing hacks
In general, margin collapsing applies to any top margin which is directly touching any bottom margin.
That includes an elements own top/bottom margins too. This is called self-collapsing, and margin collapsing happens repeatedly. Here's a quick example of both of these things together:
<div style='margin-top:30px; margin-bottom:30px;'></div>
<div style='margin-top:30px; border:1px solid black;'>
The gap above me is only 30px, not 90!
</div>
That first div entirely self-collapses, resulting in a computed space of 30px, then the second div collapses into that too, keeping the space at just 30px.
Ok, so we've now got a rough idea of what self-collapsing is. Now let's start trying to abuse that with a self-collapsing clearing div:
<div style='border:1px solid green;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<div style='clear:left;margin-top:90px;margin-bottom:90px;'></div>
I'm after the clear and look, no 90px gap!
</div>
The margin is still there though. It actually runs 90px upwards over the floats.
Next, imagine there was no text after it, and the parent had a bottom margin. By our margin collapsing rules, it should collapse upwards. Sibling elements might even collapse 'through' it, all the way up to the top. We don't want that, because it would cause some unwanted overlapping.
This part of the specification blocks this behaviour. Let's break the spec's language down to make that clearer:
If the top and bottom margins of an element with clearance are adjoining
This is describing a self-collapsing element which has cleared a float.
its margins collapse with the adjoining margins of following siblings
It's fine for other margins to collapse into it, but..
That resulting margin does not collapse with the bottom margin of the parent block.
..the very bottom margin must not collapse upwards, because that would result in our awkward overlapping case.
Here's an example of the case where the rule is applied:
<div style='border:1px solid green;'>
<!-- A parent block with a bottom margin, and no border -->
<div style='margin-bottom:50px;'>
<div style='float:left;background:red;height:100px;width:40px;'></div>
<!-- A self collapsing cleared div -->
<div style='clear:left;margin-top:50px;margin-bottom:50px;'></div>
<!-- The parents bottom margin is adjacent to our collapsed margin,
but it gets blocked from collapsing upwards. We see a gap here -->
</div>
</div>
Adding some text into that clearing div makes it no longer self collapse, but its bottom margin then safely collapses with the bottom margin of the parent instead.

Related

Why isn't the background css color showing?

Can anybody explain why no background color is displayed in the outermost div in the space of the inner div's margin?
<div style="background-color:yellow;">
<div style="margin-top:10px;background-color:black;color:white;">
Why isn't the background color yellow inside my top margin?
</div>
</div>
Divs are block elements, but they take up no space on their own (other than creating a line break) so your inner div is filling all available space within the outer div, masking the yellow background. Add some padding to the outermost div and you will see the yellow.
This is known as "margin collapse".
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.
As found in other answers, adding padding or border to the parent will prevent the margins collapsing.
I also had success applying the following CSS to the container, based on tarkabak's method described here. (Please note limited browser compatibility of :before and :after.)
.prevent-margin-collapse:before,
.prevent-margin-collapse:after
{
content: "\00a0"; /* No-break space character */
display: block;
overflow: hidden;
height: 0;
}
<div style="background-color:yellow;" class="prevent-margin-collapse">
<div style="margin-top:10px;background-color:black;color:white;">
Why isn't the background color yellow inside my top margin?
</div>
</div>
http://jsfiddle.net/yCHkW/
In addition to the other answers: This is a matter of collapsing margins. The section "Collapsing Margins Between Parent and Child Elements" should apply in this specific case.
Update: Here's a statement regarding this topic taken directly from the box model specification of CSS3 (you can find almost the same sentence within the CSS2 specification as well):
Certain adjoining margins combine to form a single margin. Those margins are said to “collapse.” Margins are adjoining if there are no nonempty content, padding or border areas or clearance to separate them.
To achieve what you want to see change your html as followed:
<div style="background-color:yellow; padding-top:10px;">
<div style="background-color:black;color:white;">
Why isn't the background color yellow inside my top margin?
</div>
</div>
The reason is that the outer div has no width set and just takes the size of its content.
I would imagine it has something to do with not inheriting any properties from elsewhere.
<div style="background-color:yellow; position: fixed;">
<div style="margin-top:10px;background-color:black;color:white;">
Why isn't the background color yellow inside my top margin?
</div>
</div>
http://jsfiddle.net/rJ3HG/

Why floating causes increased margin at the top?

Simple CSS question, I've been wondering for a while and I'd like to understand exactly how this works.
Let's say I have the following:
<div>
<p>some text</p>
<p style="float: left">some text</p>
</div>
If I remove the float: left from a given <p> element, the element and its previous sibling are stacked closer.
Why floating an element causes this increased margin at its top?
The reason for the difference is a behaviour known as collapsing margins.
Note that paragraphs have, by default, a user-agent defined top and bottom margin.
When the second paragraph does not have float: left, the bottom margin of the first paragraph and the top margin of the second paragraph are adjoining and so collapse into each other.
When the second paragraph has float: left, those two margins will no longer collapse into each other; they are no longer considered adjoining because:
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context
[...]
Following the "block formatting context" link reveals that:
Floats [...] establish new block formatting contexts for their contents.
The spec goes on to say:
Note the above rules imply that:
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
[...]
This doesn't occur for me on Chrome19.. but this would occur because of your browser's default stylesheet. If you want to prevent against this happening, use margin: 0; padding: 0; on the floated element.

How do nested vertical margin collapses work?

I am having a hard time grasping the concept of vertical margins collapsing in nested elements. I came an article at http://www.howtocreate.co.uk/tutorials/css/margincollapsing explaining how it works however am confused by its explanation. So in its example it cites that there are 2 elements as follows
<div style="margin-top:10px">
<div style="margin-top:20px">
A
</div>
</div>
Seeing that the inner div has a margin of 20px, that is what will be applied for the entire block of code. What confuses me is everything after that and not yet looking about issues with Internet Explorer 7. Would someone be able to explain it for a complete newbie to CSS in a simplified manner?
Two-ish rules to remember:
If margins touch, they collapse.
Nested items "snuggle" if only margin separates them.
Elements outside the "Flow" behave differently. That is, this behavior does not apply the same to floated, or position:fixed, or position:absolute elements.
So for this HTML (nested divs) :
<div id="outer">
<div id="inner">
A
</div>
</div>
and this initial CSS:
#outer {
margin-top:10px;
background:blue;
height: 100px;
}
#inner {
margin-top:20px;
background:red;
height: 33%;
width: 33%;
}
The margin collapses to the max of the touching margins and the nested div "snuggles" to the start of the container, like so: (See it at jsFiddle.)
But, the moment the two margins are separated -- by a border or by preceding content in the container, for example -- the margins no longer touch, so they no longer collapse.
EG, just a little, non-breaking white-space , like so:
<div id="outer">
<div id="inner">
A
</div>
</div>
kills the collapse : (See that at jsFiddle.)
Using a border, instead of leading text : (Fiddle)
A diagram may help:
In case it wasn't obvious: blue = outer div, red = inner div; I've drawn them with constant height and horizontal positioning. You can work out what happens if the height is fitted to the contents etc.
The "Before collapsing" column shows what you get if the margins aren't considered adjacent, e.g. if you draw the border of the blue/outer div; but if there is no border, then you get the "After collapsing" column. The top row switches the two margins around from the example, because I think the behaviour in this case is more intuitive; the bottom one shows the example at howtocreate and is consistent with the top row.
Two-ish rules to remember:
If margins touch, they collapse. Nested items "snuggle" if only margin separates them. Elements outside the "Flow" behave differently. That is, this behavior does not apply the same to floated, or position:fixed, or position:absolute elements.
Brock Adams is correct, but I also wanted to add that "overflow:hidden" can also prevent nested margins from collapsing.

Why is this block div affecting two floated divs?

Suppose I have three <div>s in my page,:
<div id="left" class="test" style="float:left;"></div>
<div id="right" class="test" style="float:right;"></div>
<div id="footer">footer</div>
with this css:
.test{ background:black;height:200px;width:200px;}
#footer{ background:yellow;margin:20px 0 0 0;}
What I want is:
let the "#left" float to left
let the "#right" float to right
change nothing about the "#footer", just set it to margin: 20px;
The result is below:
But I wonder why the floated divs also have the same margin as the #footer. They are floated, so they're independent of the other elements, why would the #footer could affect them?
as well as clear:both on the footer, just adding a container "wrapper" div around the the elements will stop this happening - example
actually adding clear: both; on the footer won't give you a 20px gap between the floats and the footer either, you would actually need to add the 20px bottom margin to the floats - the reasons are all linked.. to clearance or non clearance and it's interaction with Collapsing Margins
Why?
You said you wanted to know why this is happening, in your OP scenario it's because of Collapsing Margins.
You have no clearance involved in the original example, so yes the floats are removed, So the footer margin is still adjoining, therefore collapsing with, the body element, so the body element is the one getting the margin, and then because the floats are still actually inside the body they get the margin too.
As I mentioned above creating a wrapper div to "contain" the floats stops this happening because the rules of collapsing too. However you choose to contain the floats, either with overflow:hidden, or by floating the "wrapper" stops this interaction because .. from the section on collapsing margins:
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.
you see that both of the properties, float and 'overflow other than visible' are the means to "contain floated children" - actually they're establishing a new block formatting context, but in easy speak most know it as "containing floats" ;)
Now once you have that, that fixes your first bit but then if you decide to introduce clear:both on the footer, the modern browsers will not put a 20px margin between the floats and the footer.. this is actually correct.. from the section on the clear property (my bold):
Then the amount of clearance is set to
the greater of:
The amount necessary to place the border edge of the block even with
the bottom outer edge of the lowest
float that is to be cleared.
The amount necessary to place the top border edge of the block at
its hypothetical position.
In order to place the top edge of the footer below the floats (in your example) the browser has to introduce 200px of clearance, which is far more than 20px so it follows rule 1. If your top margin on the footer was 220px, the margin would be greater than the any clearance needed, so it would follow rule 2.
So, if you did actually want the footer to be 20px below the floats no matter what their heights are, you would put the 20px as a bottom margin onto the two floats, so it [the footer] would clear, via clearance rule 1, the floats with the required gap/margin, no matter which was float the longest.
PS: Don't test the above in IE7 or below - and I hope it wasn't too boring ;)
Add a clear: both to the #footer CSS. That should make the footer render below the floating divs with the margin you want.
Try this and this may solve your problem:
<div id="right" class="test" style="float:right;"></div>
<div id="left" class="test"></div>
<div id="footer">footer</div>
CSS remaining unchanged.
I made a test before finding this page that has two boxes, with the right-floated one being affected by the left block one (which comes after it) here: http://jsfiddle.net/4r75s/
The overflow trick that prevents parent divs collapsing when they only contain floated content seems to work here, that is setting overflow to hidden, auto or scroll. I wrapped them in a containing div to do it and it works: http://jsfiddle.net/4r75s/1/
#container {
overflow: hidden;
}

css float/positioniong

So I have a small div for the border, and three divs inside (see image at end). Green is full size (minus padding etc); Blue should float left and have specific width; Red should float right and also have a specific width. However I'm messing something up. Both of the blue and red divs float outside the main div. What am I doing wrong here?
Here's my current code:
<div style="border: 2px solid black; width: 630px;">
<div style="width:auto;">Lorem ipsum</div>
<div style="width:150px; float:left;">This is the blue box</div>
<div style="width:150px; float:right;">This is the red box</div>
</div>
Ideal Float http://www.mfrl.org/images/howtofloat.png
Positioning of floats is funny. Basically, the main div is not taking into account the height of the floated elements when figuring out its own height. The easiest way to resolve this is to add a clearing element after the floated elements.
This fiddle should explain itself clearly: http://jsfiddle.net/QQxb3/2/
I think that the folks who commented on your post saying that it does work must have misunderstood what you mean by "main div", because specification, which Chrome does follow and IE follows in this particular instance, would place the floated elements outside of its parent div.

Resources