The concept outlined in the specification is truly mind-bending, involving a complex interplay of the regulations for clearance and collapsing margins.
You're likely acquainted with the traditional CSS box model, where the content box is enclosed within a padding box which is contained inside a border box which in turn is surrounded by a margin box:
https://i.sstatic.net/ETl2O.png
For elements that have clear
set to something other than none
, an extra element known as clearance may be introduced into this structure.
Settings other than 'none' can potentially introduce clearance. Clearance prevents margin collapsing and serves as spacing above the top margin of an element.
In essence, in these scenarios, the box model resembles more of a configuration like this:
https://i.sstatic.net/jopxo.png
But when does clearance come into play, and how much should it be? Let's delve into the answers to those inquiries. The specification states:
Determining the clearance of an element with 'clear' set involves first establishing the hypothetical position of the element's top border edge. This position signifies where the actual top border edge would have been if the element's 'clear' property had remained 'none'.
If this hypothetical position of the element's top border edge doesn't surpass the relevant floats, then clearance comes into play, and margins collapse based on the rules in 8.3.1.
Now, let's apply this reasoning to the provided code snippet from the question asker. Remember, we aim to clarify the positioning of the third div below (backgrounds added for visualization):
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
Let's envision, as instructed by the spec, that clear
is set to none
on the third div instead of both
. How would the excerpt above appear?
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
In this scenario, the third div overlaps the two floated divs. But why is this the case? While it's allowed for floated elements to overlap block-level ones (as per the Floats spec), shouldn't the floated divs appear at the top of the body due to their order and the large top margin on the third div? Enter the world of collapsing margins and its impact, according to the Collapsing margins spec.
It turns out adjoining vertical margins collapse...
Two margins are considered adjoining only if:
- they belong to in-flow block-level boxes participating in the same block formatting context
- there's no line boxes, no clearance, no padding, and no border separating them ...
- both edges form one of the pairs:
- top margin of a box and top margin of its first in-flow child
- ...
Despite not being the body's first child, the third div is its initial in-flow child. As mentioned in the CSS positioning scheme:
An element is labeled out of flow if it's floated, absolutely positioned, or the root element. In contrast, an element is regarded as in-flow if it's not out-of-flow.
Given the float states of the first two divs, only the third div remains in-flow. Consequently, its top margin adjoins the parent's top margin, leading to margin collapse - pushing down the entire body inclusive of the floated elements. Thus, despite having a vast top margin, the third div overrides its siblings. Hence, by setting the third element's clear
to none
, we fulfill the condition where:
the element's top border edge isn't beyond the relevant floats
Hence, clearance is induced, resulting in margin collapse as per section 8.3.1.
How much clearance is called for? Browsers are presented with two options, accompanied by some explanatory notes:
The clearance amount is determined as follows:
- The greater of the required amount to align the block's border edge with the bottom outer edge of the lowest cleared float.
- The necessary amount to position the block's top border edge at the specified hypothetical position.
Alternatively, clearance equals the exact amount needed to align the block's border edge with the lowest cleared float's bottom outer edge.
Note: Both behaviors are permissible pending evaluation for compatibility with existing Web content. A future update will mandate either option.
Note: Clearances can be negative or zero.
Before diving into the application of these guidelines, consider a hurdle we face. Recall the collapsed margin from the hypothetical scenario where clear
was none
? Well, it ceases to exist in this real-world scenario where clearance calculation is crucial. Due to the presence of clearance, the collapsing margin rule dictates that margins adjacent only if:
- no line boxes, no clearance, no padding, and no borders separate them
This separation alters the relationship between the third div's top margin and the parent's top margin. To simulate this pre-clearance situation in our example, maintain clear: none
but add padding-top: 1px
to the body which disables margin collapse.
body {
padding-top: 1px;
}
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: none; margin-top: 200px; background: blue;">Main Data</div>
With the margins no longer collapsing, the third div falls comfortably underneath its floated counterparts. Following the established need for clearance due to the hypothetical margin collapse, a decision must be made regarding the amount of clearance required to:
align the block's border edge with the lowest cleared float's bottom outer edge
The sole recourse is applying a negative clearance value to the third div, uplifting its top border edge to meet the bottom outer edge (the margin edge) of the floated elements. Therefore, a clearance of -190px would be imposed if the floated elements each measure 10px in height and the third div boasts a 200px top margin. This calculation produces the final visual outcome observed by the question poser:
<div style="float: left; background: red;">Left</div>
<div style="float: right; background: green;">Right</div>
<div style="clear: both; margin-top: 200px; background: blue;">Main Data</div>
(Upon inspecting the third div in the scenario through browser developer tools, you'll still witness the 200px top margin extending above the div, thanks to the substantial negative clearance pulling up the entire margin box.)
There you have it - a seemingly intricate process demystified!