I think this is a tough one.
I use a grid system utilizing float:left
. I could rewrite it with display:inline-block
, but that would not change a thing.
Let's say we have two columns:
<div class="row"> <div class="column"> <!-- some content here --> </div> <div class="column"> <!-- some content here --> </div> </div>
If I put a block element with margin-top in it (like <h1>
) I get non collapsing margins to the content before. This is normal as it is always as such with floated elements (or display: inline-block).
But I want to have collapsing margins. I tried a lot to make it work, but it seems that every CSS that will put two elements next to each other will destroy collapsing margins to the contents above.
I know, I could use CSS to get the first-child of an element to get rid of the margin-top. But in this case it won't apply, because the content is built with a CMS and there could be an arbitrary level of element depth till I get to the element.
Is there any way of doing this without JavaScript?
Fiddle: http://jsfiddle.net/HerrSerker/ZSV3D/
You can see, that the margin-top of h1
and margin-bottom of .header
do not collapse. This is by means of float:left
of .column
.
.header { font-size: 24px; background: rgba(0,255,0,0.1); } h1 { background: silver; margin-bottom: 50px; font-size: 28px; } .column { float: left; width: 50%; background: rgba(255,0,0,0.1); } h2 { background: gold; margin-top: 50px; font-size: 24px; }
<div class="header"><h1><h1>Headerh1</h1></h1></div> <div class="row"> <div class="column"><h2><h2>Col 1, float: left</h2></h2></div> <div class="column"><h2><h2>Col 2, float: left</h2></h2></div> </div> <p>I want a 50 pixel margin between Header and the Cols, but the two margins don't collapse and I end up with 50 + = 100 pixel gap. If it would work, you wouldn't see the light red above col1 and col2</p>
I could of course use some successor operator in CSS like header + .row .column h1 { margin-top: 0;}
. But that's not what I want. What I want is a way of settings element next to each other which work with margin-collapse of contained elements.
So the situation and the question once again in short.
The problem is rather simple. I have some CSS code, which allows me to set two or more divs next to each other like float:left; width:50%. Inside of these divs are elements like h2 which have a top-margin. If inside a div before there is a h1 with bottom-margin. This situation does not allow the margins of h1 and h2 to collapse. Is there any chance of putting elements next to each other with margin-collapse and without setting the margin to zero manually?
Or otherwise. Is there any chance of settings elements next to each other without creating a new block formatting context?
------------------------------------------------------------- What it is: ┌─ .header ─────────────────┐ │ ┌─ h1 ──────────────────┐ │ │ │ │ │ │ └───────────────────────┘ │ ┄┄┄┬┄┄┄ └───────────────────────────┘ ┆ ┆ margin-bottom of h1 ┆ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┄ ┆ ┆ margin-top of h2 ┌─ .row ────────────────────┐ ┆ not collapsing │ ┌─ .col ───┐ ┌─ .col ───┐ │ ┄┄┄┴┄┄┄ │ │ ┌─ h2 ─┐ │ │ ┌─ h2 ─┐ │ │ │ │ └──────┘ │ │ └──────┘ │ │ │ └──────────┘ └──────────┘ │ └───────────────────────────┘ ------------------------------------------------------------- What I want: ┌─ .header ─────────────────┐ │ ┌─ h1 ──────────────────┐ │ │ │ │ │ │ └───────────────────────┘ │ ┄┄┄┬┄┄┄ └───────────────────────────┘ ┆ margin-bottom of h1 ┆ and margin-top of h2 ┌─ .row ────────────────────┐ ┆ collapsing │ ┌─ .col ───┐ ┌─ .col ───┐ │ ┆ │ │ ┌─ h2 ─┐ │ │ ┌─ h2 ─┐ │ │ ┄┄┄┴┄┄┄ │ │ └──────┘ │ │ └──────┘ │ │ │ └──────────┘ └──────────┘ │ └───────────────────────────┘ -------------------------------------------------------------
How to Avoid Margin Collapse. First, remember that margins should preferably be used to increase the distance between sibling elements, not to create spacing between a child and a parent. If you need to increase space within the Flow layout, reach first for padding if possible.
Margin collapsing only happens in the block-direction. This is true even if you change the writing-mode or use logical properties. The largest margin “wins”
Collapsing margins happen when two vertical margins come in contact with one another. If one margin is greater than the other, then that margin overrides the other, leaving one margin.
Margin collapsing occurs in three basic cases: Adjacent siblings. The margins of adjacent siblings are collapsed (except when the latter sibling needs to be cleared past floats). No content separating parent and descendants.
This is impossible :O
According the spec (https://www.w3.org/TR/CSS2/box.html#collapsing-margins)
Collapsing Condition:
- 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
block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes
Collapsing margins in these situation will break the rule:
- Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
- 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 boxes do not collapse (not even with their in-flow children).
- The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, unless that sibling has clearance.
- The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.
- The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.
- A box's own margins collapse if the 'min-height' property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and all of its in-flow children's margins (if any) collapse.
flex box also...(https://www.w3.org/TR/css-flexbox-1/#item-margins)
The margins of adjacent flex items do not collapse.
grid also...(https://www.w3.org/TR/css-grid-1/#item-margins)
the margins of adjacent grid items do not collapse.
It is impossible to collapse margin-top: 50px;
by using one of these solution: inline-block
, position: absolute
, float
, flex
, grid
.
If you can't set the margin to zero, maybe you can use many other method to break the margin function
for example: let h1
be inline
and let div have gold background to break the margin-top: 50px;
:
According the margin spec (https://www.w3.org/TR/CSS2/box.html#margin-properties):
Margin properties specify the width of the margin area of a box. The 'margin' shorthand property sets the margin for all four sides while the other margin properties only set their respective side. These properties apply to all elements, but vertical margins will not have any effect on non-replaced inline elements.
The only option with which you actually collapse margins, without some selector trickery or JavaScript, is the following:
Don't set margin-top: 50px
on your h1
, but on .row
See this Fiddle
HTML
<div class="header">Header is normal div</div> <div class="row"> <div class="column"><h1>Col 1 is float: left</h1></div> <div class="column"><h1>Col 2 is float: left</h1></div> </div> <p>I want a 50 pixel margin between Header and the Cols, but the two margins don't collapse and I end up with 50 + = 100 pixel gap.</p>
CSS
.header { background: silver; height: 50px; margin-bottom: 50px; font-size: 24px; } .row { margin-top: 50px; } .column { float: left; width: 50%; } h1 { background: gold; font-size: 24px; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With