7

HTML and CSS boggle my mind sometimes.

A DIV with a border shows its background color for the full height of the element and its contents. Why is it that without a border, a DIV will assume (reverse inherit?) its child's margins?

As an example, here is a JSFiddle illustrating the behavior with and without borders.

http://jsfiddle.net/ahNUX

http://jsfiddle.net/ahNUX/1/

Does anyone care to explain how this is a "feature" and not some kind of bug?

Update: adding 1px of padding to the parent is a quick fix.

Matthew
  • 8,183
  • 10
  • 37
  • 65
  • possible duplicate of [Margin on child element moves parent element](http://stackoverflow.com/questions/1762539/margin-on-child-element-moves-parent-element) – Simon East Jul 30 '15 at 04:15

2 Answers2

8

Sure. In CSS, by default, adjacent top and bottom margins overlap each other. This was a sensible workaround before the adjacent sibling selector (+) was thought of/became well-supported, as it meant that if you wrote h2 {margin-top: 3em;}, you’d have 3ems worth of space above your h2s even if there was a paragraph before it with a bottom margin of 1em.

In your second example, because the <div> doesn’t have any top or bottom padding or borders, its top and bottom margins are adjacent to the <h1>'s default top and bottom margins. Even though the <div>’s margins don’t have any height, they’re still treated as if they exist, and so the <h1>’s margins have to overlap them. As the <div>s margins are by definition outside of the background-color area of the <div>, the <h1>’s margins have to be positioned outside too.

In your first example, because the <div> has a border, its margins are no longer adjacent to the <h1>’s margins, so no overlapping occurs. You can get the same effect by adding top and bottom padding to the <div>: http://jsfiddle.net/ahNUX/7/

(I’m not sure what you mean about the <div> “reverse-inheriting” its child’s padding though. In your examples, neither the <div> nor the <h1> have any padding. The space inside the <div> in your first example is created by the <h1>’s top and bottom margin.)

Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
  • Sorry, I meant margins (edited question). H1 has it's default margin which is what I was using to illustrate the behavior. Here are fiddles using only DIVs which are more explicit. http://jsfiddle.net/ahNUX/8/ http://jsfiddle.net/ahNUX/9/ Good answer by the way. – Matthew Dec 02 '11 at 01:14
  • 1
    @Matt: no problem, your question still made sense. As to *why* collapsing margins are applied to parent/child arrangements like this, I really don’t know. It seems like it would have been fine (and more intuitive) the other way around, although I may be missing something. – Paul D. Waite Dec 02 '11 at 01:18
  • Now correct me if I am wrong (probably am) but part of your answer is that because the parent DIV has no margin, the child DIV's margin is used as the default? I would think that setting a margin on the parent DIV would "fix" this but it doesn't in this Fiddle: http://jsfiddle.net/ahNUX/10/ I agree that it seems intuitive which is why I'm wondering if this is a "feature" (notice the quotes). – Matthew Dec 02 '11 at 01:24
  • 1
    @Matt: no — the child `
    `’s margin is not *used* by the parent `
    `, it *overlaps* (or collapses into, to use the language from the spec) the parent `
    `’s margin (even when the parent `
    ` has no margin — it’s actually more accurate to think of the parent `
    ` having a zero-height margin). Whether you set a margin on the parent `
    ` or not, the child `
    `’s margin will be in the same place as the parent `
    `’s margin, i.e. outside the parent `
    `’s background-color area.
    – Paul D. Waite Dec 02 '11 at 01:31
  • 1
    Note that it’s only adjacent margins that collapse into each other. So, if you had two child `
    `s, the top margin of the first and the bottom margin of the second would collapse outside of the parent `
    `’s background area, and the adjacent margins between the two child `
    `s would collapse into each other: http://jsfiddle.net/ahNUX/13/
    – Paul D. Waite Dec 02 '11 at 01:36
  • ... starting to make sense. One more fiddle where the parent has 1px of padding - has the same effect (I think) as adding a border. In this example, because the border of the parent do not meet in the same exact spot, the collapsed margin effect does not happen: http://jsfiddle.net/ahNUX/14/ – Matthew Dec 02 '11 at 01:44
  • Yup: because the parent’s and child’s *margins* are no longer *adjacent* (due to the padding in between them), that’s why they don’t collapse. (I wouldn’t say “because the *border* of the parent do not meet in the same exact spot”, because “border” has a specific meaning in CSS, and that’s relevant here.) You’re quite correct that that’s the same effect you saw with the border. – Paul D. Waite Dec 02 '11 at 01:46
7

This is a result of collapsing margins. See http://www.w3.org/TR/CSS2/box.html#collapsing-margins

In a nutshell the top and bottom margin on the <h1> element in your example may have its margin collapse (or overlap) with another element that's above or below it, which would result in a conflict with the background color, so it's not shown. On the other hand, if you have a border, the rules change.

The spec explains it pretty well, albeit in a dry and somewhat technical tone.

Justin Michael
  • 5,634
  • 1
  • 29
  • 32