22

Just can't figure out the situation when this clever set of rules can be helpful. They break the simplicity of the box model and provide infinite source of troubles when you combine different pieces of layout together. So what is the reason?

Rules for the reference.

Update: Rules are quite logical for sibling elements, but why margins should propagate to parent elements up to the tree? What kind of problems that solves?

For example:

<div style="margin: 20px; background-color: red;">
    <div style="margin: 20px;">
        <p style="margin: 100px;">red</p>
    </div>
</div>
<div style="margin: 20px; background-color: blue;">blue</div>

Top level divs are spaced from each other by 100px.

actual
  • 2,294
  • 1
  • 19
  • 32

3 Answers3

18

This is one of the situations where it doesn't really make sense until you realise that the alternatives make less sense.

As you probably know, margins specify the distance between elements, it's not an "outer padding" that surrounds each element. If two elements with the margin 20px are next to each other, the distance between them is 20px, not 40px.

As the margin is a distance to another element, it makes sense that the distance is from the element to the surrounding elements, not to the boundary of the parent element.

If the margin would be counted to the boundary of the parent element, putting elements in a div element would introduce extra spacing between the elements eventhough the div itself has no margin or padding. The margins around an element should remain the same if you add an unstyled div around it.

Guffa
  • 640,220
  • 96
  • 678
  • 956
  • 10
    Actually, I would prefer the alternative for its clearness. Although I agree in some situations margin collapse helps. –  Sep 17 '09 at 11:32
  • 7
    That is quite logical for sibling elements. But I still not got an idea why the margins of child elemnts should affect the margins of parent element. – actual Sep 17 '09 at 11:49
  • 1
    @actual: The spacing between the child element and the boundaries of the parent element has to be the same regardless of the surrounding elements. The surrounding elements can't introduce spacing between the boundaries of the parent element and the child element, as that could change the size of the parent element, so the margin has to push the parent element away also, not just the child element. – Guffa Sep 17 '09 at 12:28
  • Thanks. Got it. Anyway, childs affecting parents, that is a little illogical for me. At least there should be a way to control that behaviour, something like "bottom-margin-overflow: hidden", but there isn't. – actual Sep 17 '09 at 12:57
  • You can also think of it as the parent and child forms a unit before the distance to other elements is calculated. To Contain the child margin in the parent you can set a padding or a border on the parent, you can use a 0.01px padding if you don't want it to take up space. – Guffa Sep 17 '09 at 14:13
  • @Guffa If the unstyled div itself has no margin or padding, couldn't it be treated as having no boundary? – Magne Jan 04 '12 at 14:51
  • 2
    @Magne: It is. That's why the collapsing margins are a bit confusing. It only affects the size of the unstyled div, the child elements have the same spacing between them with or without the unstyled parent elements. If you have two unstyled divs next to each other with child elements having margins, you see why the parents can't take up the space of the children's margins, because then the parent elements would have to overlap. – Guffa Jan 04 '12 at 15:01
  • 1
    What I like about CSS is if you say an element has something (e.g. padding) then this is not ignored. Margin collapsing sounds like something Microsoft would add if it had control of CSS... something where they're trying to help you make your document look nicer, but in reality it's only helpful if your grandma is writing a letter. If I say an element has a margin, I expect it to keep that margin without having to use CSS hacks. If I don't want a vertical margin when it's next to siblings, that's up to me and I can easily accomplish that with CSS's first-child and last-child selectors. – Gavin Sep 11 '13 at 15:52
  • @Gavin: A margin is never ignored, you only have to consider what the margin is *against*. If you want it to be an outer padding, then just wrap each element in another element, and set padding on that. – Guffa Sep 11 '13 at 18:06
  • 2
    I can't get myself to consider the current behavior of collapsing margins a logical behavior, so as far as I'm concerned if there's a margin on an element on top, and a margin on an element below, and those margins are combined into a single margin, that is ignoring one of those margins. I know what you're saying and it's correct, I just don't agree with the collapsing margins behavior at all. Like I said, it sounds like something Microsoft Word would do, not W3C. – Gavin Sep 11 '13 at 18:37
  • 1
    @Gavin: Actually, what W3C did and what MS Word would do is not that far from each other. CSS was originally intended for formatting text, not for the kind of web design we do nowadays. In a sense we are "misusing" CSS for all kinds of things, which is mostly why it seems unintuitive sometimes. – Guffa Sep 11 '13 at 20:27
  • I can kind of understand the logic for that behavior, but it still seems pretty inconsistent. The horizontal margins of adjacent in-line elements add together, rather than collapsing. Why are they treated like outer padding? – bindsniper001 Jan 14 '20 at 06:33
4

When it could be helpful?

The simplest example: a list of paragraphs and headings, each with a margin-top and margin-bottom. You want a margin on the top and bottom of the article, and between different elements.

With margin collapsing, you can do without setting special margins on the first or last item (NOT a part of the original CSS spec!) or padding the container.

But I agree, on a whole, it's a pointless feature.

Eli Krupitsky
  • 886
  • 6
  • 10
3

Consider a body of text containing multiple paragraphs. You want each paragraph to be separated by 2em, and you want the first paragraph to be separated from the preceding content by 2em, and the last paragraph to be separated from the following content by 2em.

This is easily accomplished with the following CSS, because the top and bottom margins separating the paragraphs will collapse:

p {
    margin-top: 2em
    margin-bottom: 2em;
}

If margins didn't collapse, this would result in the margins being separated by a space of 4em, not 2em. Without margin collapsing, the only way to achieve the desired effect would be to set up some additional rules for the first and last paragraphs, which would involve giving them a class or id (which would have to be maintained if the text was ever altered), or wrapping them in an otherwise-unnecessary extra element and using :first-child and :last-child, or... well, you get the idea.

I can guarantee that, if margin collapsing didn't occur, SO would have a lot of duplicate questions asking for workarounds to achieve the consistent spacing that the above rule provides :-)

NickFitz
  • 32,179
  • 8
  • 41
  • 40
  • 1
    Actually, you could solve this by simply ensuring that the preceding content and the following content has a margin.. That way you'd avoid giving the first or last paragraph a class/id and a special margin. – Magne Jan 04 '12 at 14:47
  • It would seem to me that not collapsing in this scenario would be the naive expectation. Breaks PoLS to me. Also, with collapsed margins, you can't 'uncollapse', whereas adding a little markup to handle your situation is easy enough, even if it might get repetitive. – nicodemus13 May 14 '14 at 20:57