Margin Collapse for Adjacent siblings
First, the examples below only work in Gecko based browsers like Firefox on Windows or Android. Chrome/Webkit has a long history of implementing clearance incorrectly.
I think that statement is a misinterpretation of the specification. What the specification actually says is
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context and no line boxes, no clearance, no padding and no border separate them
So what causes clearance to have an effect here? It's not the clearance of the latter sibling, but the clearance of an intervening element.
Consider this example.
.container { overflow:auto; border:2px solid;}span { float:left; width:100px; height:100px; background:red; opacity:0.2;}.container > div { height:60px; margin:20px 0; background:blue;}b { display:block; clear:left;}
<p><strong>View this in Firefox</strong></p><div class="container"> <span></span> <div></div> <b></b> <div></div></div>
Collapsed margin in CSS
The margins of #empty
collapse through, resulting in a 20px collapsed-through margin. This collapsed-through margin collapses with the 10px bottom margin of the first paragraph, and the 10px top margin of the last paragraph. This results in a 20px gap between the first and last paragraphs, since the collapsed-through margin is larger than either of their margins and therefore swallows them both.
Your observation is correct: #empty
, when its collapsed through, is rendered with its top margin. From the spec:
- [...] 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.
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.
The position that "would have been if the element had a non-zero bottom border" is the position of the element if the element's margins did not collapse through, since having a non-zero bottom border blocks the margins from collapsing through.
Margin collapse and clearance
Yes. Take a look at the below snippet [JSfiddle] in either Firefox or IE.¹
.case { width:200px; background-color:yellow; }
.container { background-color:lightblue; margin-bottom:70px; padding-top:0.01px; }.preface { float:left; height: 58px; width: 100px; border: 1px solid red; }.one .intro { clear: left; margin-top:60px; }.two .intro { clear: left; margin-top:59px; }
<div class="case one"> <div class="container"> <div class="preface"> lorem ipsum </div> <div class="intro"></div> </div> after</div><hr><div class="case two"> <div class="container"> <div class="preface"> lorem ipsum </div> <div class="intro"></div> </div> after</div>
how `clear` prevent margin collapsing?
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.
How to disable margin-collapsing?
There are two main types of margin collapse:
- Collapsing margins between adjacent elements
- Collapsing margins between parent and child elements
Using a padding or border will prevent collapse only in the latter case. Also, any value of overflow
different from its default (visible
) applied to the parent will prevent collapse. Thus, both overflow: auto
and overflow: hidden
will have the same effect. Perhaps the only difference when using hidden
is the unintended consequence of hiding content if the parent has a fixed height.
Other properties that, once applied to the parent, can help fix this behaviour are:
float: left / right
position: absolute
display: inline-block / flex / grid
You can test all of them here: http://jsfiddle.net/XB9wX/1/.
I should add that, as usual, Internet Explorer is the exception. More specifically, in IE 7 margins do not collapse when some kind of layout is specified for the parent element, such as width
.
Sources: Sitepoint's article Collapsing Margins
Is there any way to allow CSS margins to collapse through a fieldset boundary?
Yes, the fieldset
element establishes the new block formatting context (this behavior was first implemented in the browsers, so the spec incorporated this feature as part of "expected default rendering").
Unfortunately, I don't know any way to "undo" this with CSS, except completely removing the fieldset
element's box by setting it to display:contents
, which currently only gives the desired result in Chrome with the "Experimental Web Platform features" flag turned on (Firefox, although implemented display:contents
back in 2015, hasn't updated its implementation to work for "unusual elements" like form controls according to the recent addition to the spec yet).
Related Topics
CSS Positioning 70-30 with Inline-Block
How to Add Background Image in CSS
How to Get Firefox to Show an Auto Horizontal Scollbar for a Div
How to Make Header Image Responsive
CSS Targetting The Last of a Class Type That Isn't The Last-Child
How to Animate Element Again, After Animation-Fill-Mode: Forward
Susy 2.0 Change Columns at Breakpoint
How to Have Scrollbar When Position Is Negative
Build a Repetitive Selector Within a Less Loop
CSS Text Padding Difference Firefox Vs Chrome and Others
Submit Input Doesn't Get The: Active State in Ie8 When I Click on The Button's Text
Background Size Cover Ie11 Not Covering Full Area
Vertical and Horizontal Alignment of Text with CSS
How to Make a Series of <P> Elements Display Horizontally
How to Split a String (E.G. a Long Url) in a Table Cell Using CSS