Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Chrome and Firefox behave differently on margin? [duplicate]

Tags:

css

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>
like image 422
Eturcim Avatar asked Sep 28 '22 03:09

Eturcim


1 Answers

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>
like image 92
Oriol Avatar answered Oct 07 '22 21:10

Oriol