Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wanted: CSS grid system AND collapsing margins

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>&lt;h1>Headerh1&lt;/h1></h1></div> <div class="row">     <div class="column"><h2>&lt;h2>Col 1, float: left&lt;/h2></h2></div>     <div class="column"><h2>&lt;h2>Col 2, float: left&lt;/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>

Edit

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.


Edit2

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?


Edit3:

-------------------------------------------------------------       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 ─┐ │ │  ┄┄┄┴┄┄┄  │ │ └──────┘ │ │ └──────┘ │ │  │ └──────────┘ └──────────┘ │  └───────────────────────────┘        -------------------------------------------------------------       
like image 221
yunzen Avatar asked Sep 23 '13 15:09

yunzen


People also ask

How do I fix the collapse margin in CSS?

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.

Is CSS margin collapsing only happens with?

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”

What is collapsing in CSS?

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.

Which scenario margin will collapse?

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.


2 Answers

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.

like image 55
twxia Avatar answered Sep 21 '22 21:09

twxia


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; } 
like image 44
Gust van de Wal Avatar answered Sep 20 '22 21:09

Gust van de Wal