- historic bug of Flow Layout
- not in other regular layouts, e.g. Flexbox Layout, Grid Layout, etc.
- not in other irregular layouts, except also in relatively / stickily positioned elements, e.g. absolutely / fixedly positioned elements, Float Layout, etc.
- partly fixed by flow-root FC but not fully, see Adjacent siblings
- can’t fully prevent, see Adjacent siblings
- was used to eliminate excess space, instead should have used new selectors
myel ~ myel
: all myel except first of type
* ~ myel
: all myel except if first child
myel:not(:first-of-type)
/ myel:not(:last-of-type)
: all myel except first / last of type
myel:not(:first-child)
/ myel:not(:last-child)
: all myel except if first / last child
- language should never impose a guess what’s best for most users, increases complexity everywhere ⚠️
- CSS versioning should be introduced to allow removing such bugs, see Blog/A versioned Web.md ⚠️
The collapse
- two adjoining margins can collapse to one single margin
- continues recursively, i.e. many adjoining margins can collapse to one single margin
- adjoining margins: margins that have nothing between them, e.g. text content, padding, border, etc.
??? height, or min-height
- only margins in block direction collapse, i.e. vertical margins (top & bottom) in horizontal writing mode
- beware: margins in inline direction don’t collapse, i.e. horizontal margins (top & bottom) in horizontal writing mode ❗️
- only margins of block-level elements, not of inline-level elements, also not of root element
- only in flow(-root) FC
- beware: margin collapse happens even across FC boundaries, see Parent and first / last child and see Element itself ⚠️
- beware: flow-root FC fixes margin collapse across FC boundaries but not within FC, i.e. not Adjacent siblings ❗️
- beware: add comment to code if used to prevent margin collapse ❗️
- beware: don’t use border to visualise margins of box, affects margin collapse, instead use outline or browser Developer Tools ❗️
The cases
- depends on relationship of boxes in document tree
- also any combination due to recursiveness, e.g.
- margins of only child collapse with both margins of parent
- margin of child collapses with margin of parent and then with margin of grandparent
- margin of child collapses with margin of parent and then with margin of adjacent sibling of parent
- margins of empty child collapse themselves and then with margin of parent
- margins of empty only child collapse themselves and then with both margins of parent
- etc.
- beware: floats and absolutely / fixedly positioned element are treated as if they didn’t exist, i.e. can be between elements without stopping margin collapse ❗️
Adjacent siblings
- margins of adjacent siblings
- single margin is between them
- if both are positive, is largest of both (most positive)
- if one is negative, is sum of both
- if both are negative, is largest of both (most negative)
<p>Margin collapse makes the space between the boxes only 1em (largest of 1em and 1em), instead of 1em + 1em = 2em.</p>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div>Cras maximus augue et consequat porta.</div>
div {
margin: 1em 0;
background-color: lightsalmon;
border: 1px dashed red;
}
- can’t prevent since margins are always adjoining
- beware: not fixed by flow-root FC ❗️
Parent and first / last child
- block-start margin of parent and first child, block-end margin of parent and last child
- single margin is on parent, not on child, i.e. parent doesn’t contain margin of child ❗️
- beware: even if parent margin is zero, i.e. parent never contains margin of child ⚠️
- if all are positive, is largest of all (most positive)
- if at least one is negative, is sum of largest positive and largest negative
- if all are negative, is largest of all (most negative)
- can prevent by putting something between margins, e.g. text content next to child in parent, or padding, border, etc. on parent
- can prevent only for end margin also by making parent block size non-zero, e.g. height, min-height, etc. on parent
<div class="parent">
<div class="child">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
</div>
.parent {
margin: 1em 0;
background-color: lightgrey;
}
.child {
margin: 2em 0;
background-color: lightsalmon;
border: 1px dashed red;
}
- fixed with flow-root FC 🎉
- beware: don’t use legacy hacks anymore, see legacy hack 2 and 4 (3 anyways) in Float Layout#Containing floats ❗️
Element itself
- own margins of element itself
- single margin is on top
- if both are positive, is largest of both (most positive)
- if one is negative, is sum of both
- if both are negative, is largest of both (most negative)
- beware: element must be empty of text content, otherwise would have something between margins ❗️
- can prevent by putting something between margins, e.g. padding, border, etc., or making block size non-zero, e.g. height, min-height, etc.
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
<div class="empty">
</div>
<div>Cras maximus augue et consequat porta.</div>
.empty {
margin: 1em 0;
background-color: lightsalmon;
}
- fixed with flow-root FC 🎉
- beware: don’t use legacy hacks anymore, see legacy hack 2 (3 anyways) in Float Layout#Containing floats ❗️
- beware: empty box must establish flow-root FC, not be in flow-root FC ❗️
Resources