5

I am trying to understand a difference of behavior between Chrome and Firefox. I have published the following CodePen to illustrate the point.

With Firefox, the footer element sticks to the bottom of the wrapper div thanks to the margin-top: -50px applied on it. This is what I am expecting.

With Chrome (and IE), the margin-bottom of the p element pushes down the footer, making it overflow. Why is that?

html, body {
    margin: 0px;
    height: 100%
}
header {
    background-color: dodgerblue;
    opacity: 0.5;
}
#wrapper {
    background-color: tomato;
    position: relative;
    min-height: 100%;
}
 
#container p {
    background-color: lightgreen;
    width: 500px;
    /*margin-bottom: 0px;*/
}
footer {
    height: 50px;
    background-color: dodgerblue;
    margin-top: -50px;
    opacity: 0.5;
}
<body>
    <div id="wrapper">
        <header>.</header>
        <div id="container">
            <p>.</p>
        </div>
    </div>
    <footer></footer>
</body>
Eturcim
  • 798
  • 8
  • 26
  • 1
    `min-height:100%` is going to be your issue, since your wrapper div doesn't contain the footer element. – Brian Driscoll Apr 28 '15 at 16:27
  • You also have a typo in one of your colors, dogerblue instead of dodgerblue. – Mr Lister Apr 28 '15 at 16:36
  • 1
    @BrianDriscoll That wouldn't explain the differences between the browsers though; the behaviour of `margin` is supposed to be well-defined. – Mr Lister Apr 28 '15 at 16:40
  • @MrLister Given the CSS provided I believe it is behaving as expected in Chrome and IE. – Brian Driscoll Apr 28 '15 at 16:50
  • Well, I don't have a real answer (it may have something to do with collapsing margins, but I can't explain why FF and Chrome collapse their margins differently), or a real solution - the OP already has the commented-out `margin-bottom:0` in the code - but as that does the trick, why not use it? Or, a more thorough trick would be `#container p:last-child {margin-bottom:0}`,so that you can have multiple paragraphs in your container. Maybe throw in a `padding-bottom:1em` for good measure. – Mr Lister Apr 28 '15 at 17:20
  • @MrLister Indeed, the commented-out `margin-bottom` do the trick. I do not use it for the demonstration sake. The purpose of my question is to understand what's going on chrome compare to FF. – Eturcim Apr 28 '15 at 18:08
  • @BrianDriscoll You're right, replacing min-height with height is fixing the issue, but I don't see why. In both case, min-height and height, the value 100%, refers to the height of the body element wich should be the same. – Eturcim Apr 28 '15 at 18:27

2 Answers2

4

Reason

That's because the p element inside #wrapper has some margin, which may collapse.

Introduction to margin collapse

The CSS 2.1 spec says

8.3.1 Collapsing margins

In CSS, the adjoining margins of two or more boxes [...] can combine to form a single margin. Margins that combine this way are said to collapse [...]

Adjoining vertical margins collapse [...]

Your styles

Your #wrapper element has

#wrapper {
  height: auto;
  min-height: 100%;
}

Old behavior (Firefox)

An old version of the spec said

The bottom margin of an in-flow block-level element with a 'height' of 'auto' and 'min-height' less than the element's used height and 'max-height' greater than the element's used height is adjoining to its last in-flow block-level child's bottom margin if the element has no bottom padding or border.

#wrapper has height: auto. However, in case that the window is taller than its contents, min-height will be the used height (not less). Therefore, margins won't collapse.

This is the behavior observed on Firefox.

New behavior (Chrome)

However, the spec changed, and now the value of min-height does not matter:

Rephrased the rule for adjoining margins so that the 'min-height' and 'max-height' of an element have no influence over whether the element's bottom margin is adjoining to its last child's bottom margin.

The new rule is

[The] bottom margin of a last in-flow child and [the] bottom margin of its parent [are adjoining] if the parent has 'auto' computed height

Therefore, since height is auto, margins should collapse.

This is the behavior observed on Chrome.

Note

Here the current spec seems to imply that min-height: 0 is a requirement:

The above rules imply that 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 [...]

But it is not. The sentence will be clarified in CSS 2.2.

Illustration

The following snippet animates min-height to illustrate the difference of behaviors between Chrome and Firefox:

  • When min-height is smaller than content's height,
    • The used height is content's one
    • Margins collapse both on Chrome and Firefox
  • Otherwise,
    • The used height is min-height
    • Margins collapse on Chrome but not on Firefox

Therefore, when min-height reaches content's height, on Firefox there is a sudden (dis)apparition of the space caused by margin collapse.

#wrapper {
  background: orange;
  margin: 0 1em;
  -webkit-animation: animate 1s linear infinite alternate;
  animation: animate 1s linear infinite alternate;
}
footer {
  background: red;
}
p {
  margin: 1em 0;
  height: 1.75em;
  background: green;
}
@-webkit-keyframes animate {
  from { min-height: 4em; }
  to   { min-height: 6em; }
}
@keyframes animate {
  from { min-height: 4em; }
  to   { min-height: 6em; }
}
/* Content is 4.5em tall */
<div id="wrapper">
  <p>Line 1</p>
  <p>Line 2</p>
</div>
<footer>Footer</footer>
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

If you place a height of 100% on the wrapper, it will fix it. I am not 100% sure on why firefox does it right and the others don't. I researched it for an hour because it was driving me crazy, and no answer. That being said, as far as in Chrome, it makes sense because essentially you say you want the wrapper to have a MINIMUM height of 100%...but it CAN be more...so when you add the footer, it IS more...which pushes it down.

minheight: 100%;   -->   height: 100%;

But once again, not sure why it is different in the different browsers.

One thing I did notice, is that if you remove the margin-top of -50px, in firefox, it gets put right after the wrapper (no space) but if you do the same in IE and in Chrome, there is a padding sort-of on top of the footer...probably about 10 px or so (didn't measure it). This "gap" or "space" doesn't happen in firefox, but does on chrome and IE ----> which makes me think this spacing has something to do with the reason its acting different, because this spacing was the same size as what shows on the bottom of the footer (the part that passes the wrapper)

carinlynchin
  • 389
  • 1
  • 3
  • 13
  • You're right for the replacement of min-height with height, but the true question here is, why the wrapper element is more than 100% on chrome and ie ? The gap you're referring to between the wrapper and the footer (when no -margin-top is applied) is the margin bottom of the paragraph. It's like a weird marge collapsing is happening, but I don't see why. – Eturcim Apr 28 '15 at 18:29
  • @Mic75 Like I said in my comment, something to do with collapsing margins. The div shares its bottom margin with the last p in its content. If you give the p a bottom margin of, say, 40px, the space below the div will also be 40px. – Mr Lister Apr 28 '15 at 18:34
  • @MrLister You're right, marge are collapsing. Something else which confirm youre point is, if I put a padding-bottom of 1px or a border (which both prevent marge-collapsing) on the div, there is no more space below it. Finally, it seems that FF has the wrong behaviour. – Eturcim Apr 28 '15 at 18:51